From e49c8645e85160cfe1c054587e4d927d06614334 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 10 Aug 2022 16:34:10 -0500 Subject: [PATCH 01/59] [securitySolutions] resolve most @kbn/imports/no_boundary_crossing violations (#137694) --- .../common/endpoint/service/authz/index.ts | 2 - .../common/demo_data/endgame_ecs/creation.ts | 57 + .../common/demo_data/endgame_ecs/dns.ts | 59 + .../demo_data/endgame_ecs/file_events.ts | 73 + .../common/demo_data/endgame_ecs/ipv4.ts | 54 + .../demo_data/endgame_ecs/termination.ts | 50 + .../demo_data/endgame_ecs/user_logon.ts | 56 + .../demo_data/endpoint/library_load_event.ts | 63 + ...cess_execution_malware_prevention_alert.ts | 80 + .../endpoint/registry_modification_event.ts | 64 + .../public/common/demo_data/netflow.ts | 79 + .../public/common/demo_data/timeline.ts | 1117 ++++++++++++++ .../common/mock/mock_endgame_ecs_data.ts | 311 +--- .../public/common/mock/mock_timeline_data.ts | 1296 +---------------- .../public/common/mock/netflow.ts | 73 +- .../management/pages/endpoint_hosts/index.tsx | 3 - .../row_renderers_browser/examples/alerts.tsx | 5 +- .../row_renderers_browser/examples/auditd.tsx | 5 +- .../examples/auditd_file.tsx | 5 +- .../examples/library.tsx | 5 +- .../examples/netflow.tsx | 5 +- .../examples/registry.tsx | 5 +- .../examples/suricata.tsx | 5 +- .../row_renderers_browser/examples/system.tsx | 5 +- .../examples/system_dns.tsx | 5 +- .../examples/system_endgame_process.tsx | 5 +- .../examples/system_file.tsx | 5 +- .../examples/system_fim.tsx | 5 +- .../examples/system_security_event.tsx | 5 +- .../examples/system_socket.tsx | 5 +- .../examples/threat_match.tsx | 5 +- .../row_renderers_browser/examples/zeek.tsx | 5 +- .../server/endpoint/mocks.ts | 2 +- .../endpoint/routes/metadata/metadata.test.ts | 2 +- .../endpoint/services/feature_usage/index.ts | 2 - .../fleet_integration.test.ts | 2 +- .../routes/__mocks__/request_context.ts | 2 +- 37 files changed, 1804 insertions(+), 1723 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/creation.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/dns.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/file_events.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/ipv4.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/termination.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/user_logon.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endpoint/library_load_event.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endpoint/process_execution_malware_prevention_alert.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/endpoint/registry_modification_event.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/netflow.ts create mode 100644 x-pack/plugins/security_solution/public/common/demo_data/timeline.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/service/authz/index.ts b/x-pack/plugins/security_solution/common/endpoint/service/authz/index.ts index 83c1627a918251..03d14a0945184a 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/authz/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/authz/index.ts @@ -6,5 +6,3 @@ */ export { getEndpointAuthzInitialState, calculateEndpointAuthz } from './authz'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -export { getEndpointAuthzInitialStateMock } from './mocks'; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/creation.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/creation.ts new file mode 100644 index 00000000000000..781718652246d4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/creation.ts @@ -0,0 +1,57 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameCreationEvent: Ecs = { + _id: 'BcjPcG0BOpWiDweSou3g', + user: { + id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], + domain: ['Anvi-Acer'], + name: ['Arun'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['6.1'], + }, + ip: ['10.178.85.222'], + name: ['HD-obe-8bf77f54'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['creation_event'], + category: ['process'], + type: ['process_start'], + kind: ['event'], + }, + timestamp: '1569555712000', + process: { + hash: { + md5: ['62d06d7235b37895b68de56687895743'], + sha1: ['12563599116157778a22600d2a163d8112aed845'], + sha256: ['d4c97ed46046893141652e2ec0056a698f6445109949d7fcabbce331146889ee'], + }, + pid: [441684], + ppid: [8], + name: ['Microsoft.Photos.exe'], + executable: [ + 'C:\\Program Files\\WindowsApps\\Microsoft.Windows.Photos_2018.18091.17210.0_x64__8wekyb3d8bbwe\\Microsoft.Photos.exe', + ], + args: [ + 'C:\\Program Files\\WindowsApps\\Microsoft.Windows.Photos_2018.18091.17210.0_x64__8wekyb3d8bbwe\\Microsoft.Photos.exe', + '-ServerName:App.AppXzst44mncqdg84v7sv6p7yznqwssy6f7f.mca', + ], + }, + endgame: { + process_name: ['Microsoft.Photos.exe'], + pid: [441684], + parent_process_name: ['svchost.exe'], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/dns.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/dns.ts new file mode 100644 index 00000000000000..bd5061dd3bd6a6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/dns.ts @@ -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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameDnsRequest: Ecs = { + _id: 'S8jPcG0BOpWiDweSou3g', + user: { + id: ['S-1-5-18'], + domain: ['NT AUTHORITY'], + name: ['SYSTEM'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['6.1'], + }, + ip: ['10.178.85.222'], + name: ['HD-obe-8bf77f54'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['request_event'], + category: ['network'], + kind: ['event'], + }, + message: [ + 'DNS query is completed for the name %1, type %2, query options %3 with status %4 Results %5 ', + ], + timestamp: '1569555712000', + dns: { + question: { + name: ['update.googleapis.com'], + type: ['A'], + }, + resolved_ip: ['10.100.197.67'], + }, + network: { + protocol: ['dns'], + }, + process: { + pid: [443192], + name: ['GoogleUpdate.exe'], + executable: ['C:\\Program Files (x86)\\Google\\Update\\GoogleUpdate.exe'], + }, + winlog: { + event_id: [3008], + }, + endgame: { + process_name: ['GoogleUpdate.exe'], + pid: [443192], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/file_events.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/file_events.ts new file mode 100644 index 00000000000000..696d51b2e11fac --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/file_events.ts @@ -0,0 +1,73 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameFileCreateEvent: Ecs = { + _id: '98jPcG0BOpWiDweSouzg', + user: { + id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], + domain: ['Anvi-Acer'], + name: ['Arun'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['6.1'], + }, + ip: ['10.178.85.222'], + name: ['HD-obe-8bf77f54'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['file_create_event'], + category: ['file'], + kind: ['event'], + }, + timestamp: '1569555712000', + endgame: { + process_name: ['chrome.exe'], + pid: [11620], + file_path: [ + 'C:\\Users\\Arun\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\63d78c21-e593-4484-b7a9-db33cd522ddc.tmp', + ], + }, +}; + +export const demoEndgameFileDeleteEvent: Ecs = { + _id: 'OMjPcG0BOpWiDweSeuW9', + user: { + id: ['S-1-5-18'], + domain: ['NT AUTHORITY'], + name: ['SYSTEM'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['10.0'], + }, + ip: ['10.134.159.150'], + name: ['HD-v1s-d2118419'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['file_delete_event'], + category: ['file'], + kind: ['event'], + }, + timestamp: '1569555704000', + endgame: { + pid: [1084], + file_name: ['tmp000002f6'], + file_path: ['C:\\Windows\\TEMP\\tmp00000404\\tmp000002f6'], + process_name: ['AmSvc.exe'], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/ipv4.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/ipv4.ts new file mode 100644 index 00000000000000..c7d9655acb956e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/ipv4.ts @@ -0,0 +1,54 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameIpv4ConnectionAcceptEvent: Ecs = { + _id: 'LsjPcG0BOpWiDweSCNfu', + user: { + id: ['S-1-5-18'], + domain: ['NT AUTHORITY'], + name: ['SYSTEM'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['10.0'], + }, + ip: ['10.43.255.177'], + name: ['HD-gqf-0af7b4fe'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['ipv4_connection_accept_event'], + category: ['network'], + kind: ['event'], + }, + timestamp: '1569555676000', + network: { + community_id: ['1:network-community_id'], + transport: ['tcp'], + }, + process: { + pid: [1084], + name: ['AmSvc.exe'], + executable: ['C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe'], + }, + source: { + ip: ['127.0.0.1'], + port: [49306], + }, + destination: { + port: [49305], + ip: ['127.0.0.1'], + }, + endgame: { + pid: [1084], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/termination.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/termination.ts new file mode 100644 index 00000000000000..adab55d27c697b --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/termination.ts @@ -0,0 +1,50 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameTerminationEvent: Ecs = { + _id: '2MjPcG0BOpWiDweSoutC', + user: { + id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], + domain: ['Anvi-Acer'], + name: ['Arun'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['6.1'], + }, + ip: ['10.178.85.222'], + name: ['HD-obe-8bf77f54'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['termination_event'], + category: ['process'], + kind: ['event'], + }, + timestamp: '1569555712000', + process: { + hash: { + md5: ['bd4401441a21bf1abce6404f4231db4d'], + sha1: ['797255e72d5ed5c058d4785950eba7abaa057653'], + sha256: ['87976f3430cc99bc939e0694247c0759961a49832b87218f4313d6fc0bc3a776'], + }, + pid: [442384], + ppid: [8], + name: ['RuntimeBroker.exe'], + executable: ['C:\\Windows\\System32\\RuntimeBroker.exe'], + }, + endgame: { + pid: [442384], + process_name: ['RuntimeBroker.exe'], + exit_code: [0], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/user_logon.ts b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/user_logon.ts new file mode 100644 index 00000000000000..ebc3cdcf1afe68 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endgame_ecs/user_logon.ts @@ -0,0 +1,56 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndgameUserLogon: Ecs = { + _id: 'QsjPcG0BOpWiDweSeuRE', + user: { + id: ['S-1-5-18'], + domain: ['NT AUTHORITY'], + name: ['SYSTEM'], + }, + host: { + os: { + platform: ['windows'], + name: ['Windows'], + version: ['10.0'], + }, + ip: ['10.134.159.150'], + name: ['HD-v1s-d2118419'], + }, + event: { + module: ['endgame'], + dataset: ['esensor'], + action: ['user_logon'], + category: ['authentication'], + type: ['authentication_success'], + kind: ['event'], + }, + message: [ + 'An account was successfully logged on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWIN-Q3DOP1UKA81$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3e7\r\n\r\nLogon Type:\t\t\t5\r\n\r\nNew Logon:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3e7\r\n\tLogon GUID:\t\t{00000000-0000-0000-0000-000000000000}\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x1b0\r\n\tProcess Name:\t\tC:\\Windows\\System32\\services.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\t\r\n\tSource Network Address:\t-\r\n\tSource Port:\t\t-\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tAdvapi \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon session is created. It is generated on the computer that was accessed.\r\n\r\nThe subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe logon type field indicates the kind of logon that occurred. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe New Logon fields indicate the account for whom the new logon was created, i.e. the account that was logged on.\r\n\r\nThe network fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Logon GUID is a unique identifier that can be used to correlate this event with a KDC event.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.', + ], + timestamp: '1569555704000', + process: { + pid: [432], + name: ['C:\\Windows\\System32\\services.exe'], + executable: ['C:\\Windows\\System32\\services.exe'], + }, + winlog: { + event_id: [4624], + }, + endgame: { + target_logon_id: ['0x3e7'], + pid: [432], + process_name: ['C:\\Windows\\System32\\services.exe'], + logon_type: [5], + subject_user_name: ['WIN-Q3DOP1UKA81$'], + subject_logon_id: ['0x3e7'], + target_user_name: ['SYSTEM'], + target_domain_name: ['NT AUTHORITY'], + }, +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endpoint/library_load_event.ts b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/library_load_event.ts new file mode 100644 index 00000000000000..039115624ab910 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/library_load_event.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Ecs } from '../../../../common/ecs'; + +export const demoEndpointLibraryLoadEvent: Ecs = { + file: { + path: ['C:\\Windows\\System32\\bcrypt.dll'], + hash: { + md5: ['00439016776de367bad087d739a03797'], + sha1: ['2c4ba5c1482987d50a182bad915f52cd6611ee63'], + sha256: ['e70f5d8f87aab14e3160227d38387889befbe37fa4f8f5adc59eff52804b35fd'], + }, + name: ['bcrypt.dll'], + }, + host: { + os: { + full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1697)'], + name: ['Windows'], + version: ['1809 (10.0.17763.1697)'], + family: ['windows'], + kernel: ['1809 (10.0.17763.1697)'], + platform: ['windows'], + }, + mac: ['aa:bb:cc:dd:ee:ff'], + name: ['win2019-endpoint-1'], + architecture: ['x86_64'], + ip: ['10.1.2.3'], + id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], + }, + event: { + category: ['library'], + kind: ['event'], + created: ['2021-02-05T21:27:23.921Z'], + module: ['endpoint'], + action: ['load'], + type: ['start'], + id: ['LzzWB9jjGmCwGMvk++++Da5H'], + dataset: ['endpoint.events.library'], + }, + process: { + name: ['sshd.exe'], + pid: [9644], + entity_id: [ + 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTk2NDQtMTMyNTcwMzQwNDEuNzgyMTczODAw', + ], + executable: ['C:\\Program Files\\OpenSSH-Win64\\sshd.exe'], + }, + agent: { + type: ['endpoint'], + }, + user: { + name: ['SYSTEM'], + domain: ['NT AUTHORITY'], + }, + message: ['Endpoint DLL load event'], + timestamp: '2021-02-05T21:27:23.921Z', + _id: 'IAUYdHcBGrBB52F2zo8Q', +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endpoint/process_execution_malware_prevention_alert.ts b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/process_execution_malware_prevention_alert.ts new file mode 100644 index 00000000000000..1a3657e8672614 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/process_execution_malware_prevention_alert.ts @@ -0,0 +1,80 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndpointProcessExecutionMalwarePreventionAlert: Ecs = { + process: { + hash: { + md5: ['177afc1eb0be88eb9983fb74111260c4'], + sha256: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb'], + sha1: ['f573b85e9beb32121f1949217947b2adc6749e3d'], + }, + entity_id: [ + 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTY5MjAtMTMyNDg5OTk2OTAuNDgzMzA3NzAw', + ], + executable: [ + 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', + ], + name: [ + 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', + ], + pid: [6920], + args: [ + 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', + ], + }, + host: { + os: { + full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1518)'], + name: ['Windows'], + version: ['1809 (10.0.17763.1518)'], + platform: ['windows'], + family: ['windows'], + kernel: ['1809 (10.0.17763.1518)'], + }, + mac: ['aa:bb:cc:dd:ee:ff'], + architecture: ['x86_64'], + ip: ['10.1.2.3'], + id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], + name: ['win2019-endpoint-1'], + }, + file: { + mtime: ['2020-11-04T21:40:51.494Z'], + path: [ + 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', + ], + owner: ['sean'], + hash: { + md5: ['177afc1eb0be88eb9983fb74111260c4'], + sha256: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb'], + sha1: ['f573b85e9beb32121f1949217947b2adc6749e3d'], + }, + name: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe'], + extension: ['exe'], + size: [1604112], + }, + event: { + category: ['malware', 'intrusion_detection', 'process'], + outcome: ['success'], + severity: [73], + code: ['malicious_file'], + action: ['execution'], + id: ['LsuMZVr+sdhvehVM++++Gp2Y'], + kind: ['alert'], + created: ['2020-11-04T21:41:30.533Z'], + module: ['endpoint'], + type: ['info', 'start', 'denied'], + dataset: ['endpoint.alerts'], + }, + agent: { + type: ['endpoint'], + }, + timestamp: '2020-11-04T21:41:30.533Z', + message: ['Malware Prevention Alert'], + _id: '0dA2lXUBn9bLIbfPkY7d', +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/endpoint/registry_modification_event.ts b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/registry_modification_event.ts new file mode 100644 index 00000000000000..2f34360b464438 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/endpoint/registry_modification_event.ts @@ -0,0 +1,64 @@ +/* + * 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 type { Ecs } from '../../../../common/ecs'; + +export const demoEndpointRegistryModificationEvent: Ecs = { + host: { + os: { + full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1697)'], + name: ['Windows'], + version: ['1809 (10.0.17763.1697)'], + family: ['windows'], + kernel: ['1809 (10.0.17763.1697)'], + platform: ['windows'], + }, + mac: ['aa:bb:cc:dd:ee:ff'], + name: ['win2019-endpoint-1'], + architecture: ['x86_64'], + ip: ['10.1.2.3'], + id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], + }, + event: { + category: ['registry'], + kind: ['event'], + created: ['2021-02-04T13:44:31.559Z'], + module: ['endpoint'], + action: ['modification'], + type: ['change'], + id: ['LzzWB9jjGmCwGMvk++++CbOn'], + dataset: ['endpoint.events.registry'], + }, + process: { + name: ['GoogleUpdate.exe'], + pid: [7408], + entity_id: [ + 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTc0MDgtMTMyNTY5MTk4NDguODY4NTI0ODAw', + ], + executable: ['C:\\Program Files (x86)\\Google\\Update\\GoogleUpdate.exe'], + }, + registry: { + hive: ['HKLM'], + key: [ + 'SOFTWARE\\WOW6432Node\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}\\CurrentState', + ], + path: [ + 'HKLM\\SOFTWARE\\WOW6432Node\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}\\CurrentState\\StateValue', + ], + value: ['StateValue'], + }, + agent: { + type: ['endpoint'], + }, + user: { + name: ['SYSTEM'], + domain: ['NT AUTHORITY'], + }, + message: ['Endpoint registry event'], + timestamp: '2021-02-04T13:44:31.559Z', + _id: '4cxLbXcBGrBB52F2uOfF', +}; diff --git a/x-pack/plugins/security_solution/public/common/demo_data/netflow.ts b/x-pack/plugins/security_solution/public/common/demo_data/netflow.ts new file mode 100644 index 00000000000000..51f281a4b056b4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/netflow.ts @@ -0,0 +1,79 @@ +/* + * 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 { ONE_MILLISECOND_AS_NANOSECONDS } from '../../timelines/components/formatted_duration/helpers'; +import type { Ecs } from '../../../common/ecs'; + +/** Returns mock data for testing the Netflow component */ +export const getDemoNetflowData = (): Ecs => ({ + destination: { + bytes: [40], + geo: { + city_name: ['New York'], + continent_name: ['North America'], + country_iso_code: ['US'], + country_name: ['United States'], + region_name: ['New York'], + }, + ip: ['10.1.2.3'], + packets: [1], + port: [80], + }, + event: { + action: ['network_flow'], + category: ['network_traffic'], + duration: [ONE_MILLISECOND_AS_NANOSECONDS], + end: ['2018-11-12T19:03:25.936Z'], + start: ['2018-11-12T19:03:25.836Z'], + }, + _id: 'abcd', + network: { + bytes: [100], + community_id: ['we.live.in.a'], + direction: ['outgoing'], + packets: [3], + protocol: ['http'], + transport: ['tcp'], + }, + process: { + name: ['rat'], + }, + source: { + bytes: [60], + geo: { + city_name: ['Atlanta'], + continent_name: ['North America'], + country_iso_code: ['US'], + country_name: ['United States'], + region_name: ['Georgia'], + }, + ip: ['192.168.1.2'], + packets: [2], + port: [9987], + }, + timestamp: '2018-11-12T19:03:25.936Z', + tls: { + client_certificate: { + fingerprint: { + sha1: ['tls.client_certificate.fingerprint.sha1-value'], + }, + }, + fingerprints: { + ja3: { + hash: ['tls.fingerprints.ja3.hash-value'], + }, + }, + server_certificate: { + fingerprint: { + sha1: ['tls.server_certificate.fingerprint.sha1-value'], + }, + }, + }, + user: { + name: ['first.last'], + }, +}); diff --git a/x-pack/plugins/security_solution/public/common/demo_data/timeline.ts b/x-pack/plugins/security_solution/public/common/demo_data/timeline.ts new file mode 100644 index 00000000000000..90a4c2221d16cf --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/demo_data/timeline.ts @@ -0,0 +1,1117 @@ +/* + * 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 type { TimelineItem } from '../../../common/search_strategy/timeline'; + +export const demoTimelineData: TimelineItem[] = [ + { + _id: '1', + data: [ + { field: '@timestamp', value: ['2018-11-05T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'event.action', value: ['Action'] }, + { field: 'host.name', value: ['apache'] }, + { field: 'source.ip', value: ['192.168.0.1'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['john.dee'] }, + ], + ecs: { + _id: '1', + timestamp: '2018-11-05T19:03:25.937Z', + host: { name: ['apache'], ip: ['192.168.0.1'] }, + event: { + id: ['1'], + action: ['Action'], + category: ['Access'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.1'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['1'], name: ['john.dee'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '3', + data: [ + { field: '@timestamp', value: ['2018-11-07T19:03:25.937Z'] }, + { field: 'event.severity', value: ['1'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['nginx'] }, + { field: 'source.ip', value: ['192.168.0.3'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['evan.davis'] }, + ], + ecs: { + _id: '3', + timestamp: '2018-11-07T19:03:25.937Z', + host: { name: ['nginx'], ip: ['192.168.0.1'] }, + event: { + id: ['3'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [1], + }, + source: { ip: ['192.168.0.3'], port: [443] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['3'], name: ['evan.davis'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '4', + data: [ + { field: '@timestamp', value: ['2018-11-08T19:03:25.937Z'] }, + { field: 'event.severity', value: ['1'] }, + { field: 'event.category', value: ['Attempted Administrator Privilege Gain'] }, + { field: 'host.name', value: ['suricata'] }, + { field: 'source.ip', value: ['192.168.0.3'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jenny.jones'] }, + ], + ecs: { + _id: '4', + timestamp: '2018-11-08T19:03:25.937Z', + host: { name: ['suricata'], ip: ['192.168.0.1'] }, + event: { + id: ['4'], + category: ['Attempted Administrator Privilege Gain'], + type: ['Alert'], + module: ['suricata'], + severity: [1], + }, + source: { ip: ['192.168.0.3'], port: [53] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + suricata: { + eve: { + flow_id: [4], + proto: [''], + alert: { + signature: [ + 'ET EXPLOIT NETGEAR WNR2000v5 hidden_lang_avi Stack Overflow (CVE-2016-10174)', + ], + signature_id: [4], + }, + }, + }, + user: { id: ['4'], name: ['jenny.jones'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '5', + data: [ + { field: '@timestamp', value: ['2018-11-09T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.3'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['becky.davis'] }, + ], + ecs: { + _id: '5', + timestamp: '2018-11-09T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['5'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.3'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['5'], name: ['becky.davis'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '6', + data: [ + { field: '@timestamp', value: ['2018-11-10T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['braden.davis'] }, + { field: 'source.ip', value: ['192.168.0.6'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + ], + ecs: { + _id: '6', + timestamp: '2018-11-10T19:03:25.937Z', + host: { name: ['braden.davis'], ip: ['192.168.0.1'] }, + event: { + id: ['6'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.6'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '8', + data: [ + { field: '@timestamp', value: ['2018-11-12T19:03:25.937Z'] }, + { field: 'event.severity', value: ['2'] }, + { field: 'event.category', value: ['Web Application Attack'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.8'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '8', + timestamp: '2018-11-12T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['8'], + category: ['Web Application Attack'], + type: ['Alert'], + module: ['suricata'], + severity: [2], + }, + suricata: { + eve: { + flow_id: [8], + proto: [''], + alert: { + signature: ['ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Cookie'], + signature_id: [8], + }, + }, + }, + source: { ip: ['192.168.0.8'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['8'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '7', + data: [ + { field: '@timestamp', value: ['2018-11-11T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.7'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '7', + timestamp: '2018-11-11T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['7'], + category: ['Access'], + type: ['HTTP Request'], + module: ['apache'], + severity: [3], + }, + source: { ip: ['192.168.0.7'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['7'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '9', + data: [ + { field: '@timestamp', value: ['2018-11-13T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.9'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '9', + timestamp: '2018-11-13T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['9'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.9'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['9'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '10', + data: [ + { field: '@timestamp', value: ['2018-11-14T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.10'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '10', + timestamp: '2018-11-14T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['10'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.10'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['10'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '11', + data: [ + { field: '@timestamp', value: ['2018-11-15T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.11'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '11', + timestamp: '2018-11-15T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['11'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.11'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['11'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '12', + data: [ + { field: '@timestamp', value: ['2018-11-16T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.12'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['jone.doe'] }, + ], + ecs: { + _id: '12', + timestamp: '2018-11-16T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['12'], + category: ['Access'], + type: ['HTTP Request'], + module: ['nginx'], + severity: [3], + }, + source: { ip: ['192.168.0.12'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['12'], name: ['jone.doe'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '2', + data: [ + { field: '@timestamp', value: ['2018-11-06T19:03:25.937Z'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Authentication'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.2'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['joe.bob'] }, + ], + ecs: { + _id: '2', + timestamp: '2018-11-06T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['2'], + category: ['Authentication'], + type: ['Authentication Success'], + module: ['authlog'], + severity: [3], + }, + source: { ip: ['192.168.0.2'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['1'], name: ['joe.bob'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '13', + data: [ + { field: '@timestamp', value: ['2018-13-12T19:03:25.937Z'] }, + { field: 'event.severity', value: ['1'] }, + { field: 'event.category', value: ['Web Application Attack'] }, + { field: 'host.name', value: ['joe.computer'] }, + { field: 'source.ip', value: ['192.168.0.8'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + ], + ecs: { + _id: '13', + timestamp: '2018-13-12T19:03:25.937Z', + host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, + event: { + id: ['13'], + category: ['Web Application Attack'], + type: ['Alert'], + module: ['suricata'], + severity: [1], + }, + suricata: { + eve: { + flow_id: [13], + proto: [''], + alert: { + signature: ['ET WEB_SERVER Possible Attempt in HTTP Cookie'], + signature_id: [13], + }, + }, + }, + source: { ip: ['192.168.0.8'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '14', + data: [ + { field: '@timestamp', value: ['2019-03-07T05:06:51.000Z'] }, + { field: 'host.name', value: ['zeek-franfurt'] }, + { field: 'source.ip', value: ['192.168.26.101'] }, + { field: 'destination.ip', value: ['192.168.238.205'] }, + ], + ecs: { + _id: '14', + timestamp: '2019-03-07T05:06:51.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.connection'], + }, + host: { + id: ['37c81253e0fc4c46839c19b981be5177'], + name: ['zeek-franfurt'], + ip: ['207.154.238.205', '10.19.0.5', 'fe80::d82b:9aff:fe0d:1e12'], + }, + source: { ip: ['185.176.26.101'], port: [44059] }, + destination: { ip: ['207.154.238.205'], port: [11568] }, + geo: { region_name: ['New York'], country_iso_code: ['US'] }, + network: { transport: ['tcp'] }, + zeek: { + session_id: ['C8DRTq362Fios6hw16'], + connection: { + local_resp: [false], + local_orig: [false], + missed_bytes: [0], + state: ['REJ'], + history: ['Sr'], + }, + }, + }, + }, + { + _id: '15', + data: [ + { field: '@timestamp', value: ['2019-03-07T00:51:28.000Z'] }, + { field: 'host.name', value: ['suricata-zeek-singapore'] }, + { field: 'source.ip', value: ['192.168.35.240'] }, + { field: 'destination.ip', value: ['192.168.67.3'] }, + ], + ecs: { + _id: '15', + timestamp: '2019-03-07T00:51:28.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.dns'], + }, + host: { + id: ['af3fddf15f1d47979ce817ba0df10c6e'], + name: ['suricata-zeek-singapore'], + ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], + }, + source: { ip: ['206.189.35.240'], port: [57475] }, + destination: { ip: ['67.207.67.3'], port: [53] }, + geo: { region_name: ['New York'], country_iso_code: ['US'] }, + network: { transport: ['udp'] }, + zeek: { + session_id: ['CyIrMA1L1JtLqdIuol'], + dns: { + AA: [false], + RD: [false], + trans_id: [65252], + RA: [false], + TC: [false], + }, + }, + }, + }, + { + _id: '16', + data: [ + { field: '@timestamp', value: ['2019-03-05T07:00:20.000Z'] }, + { field: 'host.name', value: ['suricata-zeek-singapore'] }, + { field: 'source.ip', value: ['192.168.35.240'] }, + { field: 'destination.ip', value: ['192.168.164.26'] }, + ], + ecs: { + _id: '16', + timestamp: '2019-03-05T07:00:20.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.http'], + }, + host: { + id: ['af3fddf15f1d47979ce817ba0df10c6e'], + name: ['suricata-zeek-singapore'], + ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], + }, + source: { ip: ['206.189.35.240'], port: [36220] }, + destination: { ip: ['192.241.164.26'], port: [80] }, + geo: { region_name: ['New York'], country_iso_code: ['US'] }, + http: { + version: ['1.1'], + request: { body: { bytes: [0] } }, + response: { status_code: [302], body: { bytes: [154] } }, + }, + zeek: { + session_id: ['CZLkpC22NquQJOpkwe'], + + http: { + resp_mime_types: ['text/html'], + trans_depth: ['3'], + status_msg: ['Moved Temporarily'], + resp_fuids: ['FzeujEPP7GTHmYPsc'], + tags: [], + }, + }, + }, + }, + { + _id: '17', + data: [ + { field: '@timestamp', value: ['2019-02-28T22:36:28.000Z'] }, + { field: 'host.name', value: ['zeek-franfurt'] }, + { field: 'source.ip', value: ['192.168.77.171'] }, + ], + ecs: { + _id: '17', + timestamp: '2019-02-28T22:36:28.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.notice'], + }, + host: { + id: ['37c81253e0fc4c46839c19b981be5177'], + name: ['zeek-franfurt'], + ip: ['207.154.238.205', '10.19.0.5', 'fe80::d82b:9aff:fe0d:1e12'], + }, + source: { ip: ['8.42.77.171'] }, + zeek: { + notice: { + suppress_for: [3600], + msg: ['8.42.77.171 scanned at least 15 unique ports of host 207.154.238.205 in 0m0s'], + note: ['Scan::Port_Scan'], + sub: ['remote'], + dst: ['207.154.238.205'], + dropped: [false], + peer_descr: ['bro'], + }, + }, + }, + }, + { + _id: '18', + data: [ + { field: '@timestamp', value: ['2019-02-22T21:12:13.000Z'] }, + { field: 'host.name', value: ['zeek-sensor-amsterdam'] }, + { field: 'source.ip', value: ['192.168.66.184'] }, + { field: 'destination.ip', value: ['192.168.95.15'] }, + ], + ecs: { + _id: '18', + timestamp: '2019-02-22T21:12:13.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.ssl'], + }, + host: { id: ['2ce8b1e7d69e4a1d9c6bcddc473da9d9'], name: ['zeek-sensor-amsterdam'] }, + source: { ip: ['188.166.66.184'], port: [34514] }, + destination: { ip: ['91.189.95.15'], port: [443] }, + geo: { region_name: ['England'], country_iso_code: ['GB'] }, + zeek: { + session_id: ['CmTxzt2OVXZLkGDaRe'], + ssl: { + cipher: ['TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'], + established: [false], + resumed: [false], + version: ['TLSv12'], + }, + }, + }, + }, + { + _id: '19', + data: [ + { field: '@timestamp', value: ['2019-03-03T04:26:38.000Z'] }, + { field: 'host.name', value: ['suricata-zeek-singapore'] }, + ], + ecs: { + _id: '19', + timestamp: '2019-03-03T04:26:38.000Z', + event: { + module: ['zeek'], + dataset: ['zeek.files'], + }, + host: { + id: ['af3fddf15f1d47979ce817ba0df10c6e'], + name: ['suricata-zeek-singapore'], + ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], + }, + zeek: { + session_id: ['Cu0n232QMyvNtzb75j'], + files: { + session_ids: ['Cu0n232QMyvNtzb75j'], + timedout: [false], + local_orig: [false], + tx_host: ['5.101.111.50'], + source: ['HTTP'], + is_orig: [false], + overflow_bytes: [0], + sha1: ['fa5195a5dfacc9d1c68d43600f0e0262cad14dde'], + duration: [0], + depth: [0], + analyzers: ['MD5', 'SHA1'], + mime_type: ['text/plain'], + rx_host: ['206.189.35.240'], + total_bytes: [88722], + fuid: ['FePz1uVEVCZ3I0FQi'], + seen_bytes: [1198], + missing_bytes: [0], + md5: ['f7653f1951693021daa9e6be61226e32'], + }, + }, + }, + }, + { + _id: '20', + data: [ + { field: '@timestamp', value: ['2019-03-13T05:42:11.815Z'] }, + { field: 'event.category', value: ['audit-rule'] }, + { field: 'host.name', value: ['zeek-sanfran'] }, + { field: 'process.args', value: ['gpgconf', '--list-dirs', 'agent-socket'] }, + ], + ecs: { + _id: '20', + timestamp: '2019-03-13T05:42:11.815Z', + event: { + action: ['executed'], + module: ['auditd'], + category: ['audit-rule'], + }, + host: { + id: ['f896741c3b3b44bdb8e351a4ab6d2d7c'], + name: ['zeek-sanfran'], + ip: ['134.209.63.134', '10.46.0.5', 'fe80::a0d9:16ff:fecf:e70b'], + }, + user: { name: ['alice'] }, + process: { + pid: [5402], + name: ['gpgconf'], + ppid: [5401], + args: ['gpgconf', '--list-dirs', 'agent-socket'], + executable: ['/usr/bin/gpgconf'], + title: ['gpgconf --list-dirs agent-socket'], + working_directory: ['/'], + }, + }, + }, + { + _id: '21', + data: [ + { field: '@timestamp', value: ['2019-03-14T22:30:25.527Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'source.ip', value: ['192.168.77.171'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '21', + timestamp: '2019-03-14T22:30:25.527Z', + event: { + action: ['logged-in'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['14'], + data: { terminal: ['/dev/pts/0'], op: ['login'] }, + summary: { + actor: { primary: ['alice'], secondary: ['alice'] }, + object: { primary: ['/dev/pts/0'], secondary: ['8.42.77.171'], type: ['user-session'] }, + how: ['/usr/sbin/sshd'], + }, + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + source: { ip: ['8.42.77.171'] }, + user: { name: ['root'] }, + process: { + pid: [17471], + executable: ['/usr/sbin/sshd'], + }, + }, + }, + { + _id: '22', + data: [ + { field: '@timestamp', value: ['2019-03-13T03:35:21.614Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['suricata-bangalore'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '22', + timestamp: '2019-03-13T03:35:21.614Z', + event: { + action: ['disposed-credentials'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['340'], + data: { acct: ['alice'], terminal: ['ssh'], op: ['PAM:setcred'] }, + summary: { + actor: { primary: ['alice'], secondary: ['alice'] }, + object: { primary: ['ssh'], secondary: ['8.42.77.171'], type: ['user-session'] }, + how: ['/usr/sbin/sshd'], + }, + }, + host: { + id: ['0a63559c1acf4c419d979c4b4d8b83ff'], + name: ['suricata-bangalore'], + ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], + }, + user: { name: ['root'] }, + process: { + pid: [21202], + executable: ['/usr/sbin/sshd'], + }, + }, + }, + { + _id: '23', + data: [ + { field: '@timestamp', value: ['2019-03-13T03:35:21.614Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['suricata-bangalore'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '23', + timestamp: '2019-03-13T03:35:21.614Z', + event: { + action: ['ended-session'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['340'], + data: { acct: ['alice'], terminal: ['ssh'], op: ['PAM:session_close'] }, + summary: { + actor: { primary: ['alice'], secondary: ['alice'] }, + object: { primary: ['ssh'], secondary: ['8.42.77.171'], type: ['user-session'] }, + how: ['/usr/sbin/sshd'], + }, + }, + host: { + id: ['0a63559c1acf4c419d979c4b4d8b83ff'], + name: ['suricata-bangalore'], + ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], + }, + user: { name: ['root'] }, + process: { + pid: [21202], + executable: ['/usr/sbin/sshd'], + }, + }, + }, + { + _id: '24', + data: [ + { field: '@timestamp', value: ['2019-03-18T23:17:01.645Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '24', + timestamp: '2019-03-18T23:17:01.645Z', + event: { + action: ['acquired-credentials'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['unset'], + data: { acct: ['root'], terminal: ['cron'], op: ['PAM:setcred'] }, + summary: { + actor: { primary: ['unset'], secondary: ['root'] }, + object: { primary: ['cron'], type: ['user-session'] }, + how: ['/usr/sbin/cron'], + }, + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + user: { name: ['root'] }, + process: { + pid: [9592], + executable: ['/usr/sbin/cron'], + }, + }, + }, + { + _id: '25', + data: [ + { field: '@timestamp', value: ['2019-03-19T01:17:01.336Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['siem-kibana'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '25', + timestamp: '2019-03-19T01:17:01.336Z', + event: { + action: ['started-session'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['2908'], + data: { acct: ['root'], terminal: ['cron'], op: ['PAM:session_open'] }, + summary: { + actor: { primary: ['root'], secondary: ['root'] }, + object: { primary: ['cron'], type: ['user-session'] }, + how: ['/usr/sbin/cron'], + }, + }, + host: { id: ['aa7ca589f1b8220002f2fc61c64cfbf1'], name: ['siem-kibana'] }, + user: { name: ['root'] }, + process: { + pid: [725], + executable: ['/usr/sbin/cron'], + }, + }, + }, + { + _id: '26', + data: [ + { field: '@timestamp', value: ['2019-03-13T03:34:08.890Z'] }, + { field: 'event.category', value: ['user-login'] }, + { field: 'host.name', value: ['suricata-bangalore'] }, + { field: 'user.name', value: ['alice'] }, + ], + ecs: { + _id: '26', + timestamp: '2019-03-13T03:34:08.890Z', + event: { + action: ['was-authorized'], + module: ['auditd'], + category: ['user-login'], + }, + auditd: { + result: ['success'], + session: ['338'], + data: { terminal: ['/dev/pts/0'] }, + summary: { + actor: { primary: ['root'], secondary: ['alice'] }, + object: { primary: ['/dev/pts/0'], type: ['user-session'] }, + how: ['/sbin/pam_tally2'], + }, + }, + host: { + id: ['0a63559c1acf4c419d979c4b4d8b83ff'], + name: ['suricata-bangalore'], + ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], + }, + user: { name: ['alice'] }, + process: { + pid: [21170], + executable: ['/sbin/pam_tally2'], + }, + }, + }, + { + _id: '27', + data: [ + { field: '@timestamp', value: ['2019-03-22T19:13:11.026Z'] }, + { field: 'event.action', value: ['connected-to'] }, + { field: 'event.category', value: ['audit-rule'] }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'destination.ip', value: ['192.168.216.34'] }, + { field: 'user.name', value: ['alice'] }, + ], + ecs: { + _id: '27', + timestamp: '2019-03-22T19:13:11.026Z', + event: { + action: ['connected-to'], + module: ['auditd'], + category: ['audit-rule'], + }, + auditd: { + result: ['success'], + session: ['246'], + summary: { + actor: { primary: ['alice'], secondary: ['alice'] }, + object: { primary: ['192.168.216.34'], secondary: ['80'], type: ['socket'] }, + how: ['/usr/bin/wget'], + }, + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + destination: { ip: ['192.168.216.34'], port: [80] }, + user: { name: ['alice'] }, + process: { + pid: [1490], + name: ['wget'], + ppid: [1476], + executable: ['/usr/bin/wget'], + title: ['wget www.example.com'], + }, + }, + }, + { + _id: '28', + data: [ + { field: '@timestamp', value: ['2019-03-26T22:12:18.609Z'] }, + { field: 'event.action', value: ['opened-file'] }, + { field: 'event.category', value: ['audit-rule'] }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'user.name', value: ['root'] }, + ], + ecs: { + _id: '28', + timestamp: '2019-03-26T22:12:18.609Z', + event: { + action: ['opened-file'], + module: ['auditd'], + category: ['audit-rule'], + }, + auditd: { + result: ['success'], + session: ['242'], + summary: { + actor: { primary: ['unset'], secondary: ['root'] }, + object: { primary: ['/proc/15990/attr/current'], type: ['file'] }, + how: ['/lib/systemd/systemd-journald'], + }, + }, + file: { + path: ['/proc/15990/attr/current'], + device: ['00:00'], + inode: ['27672309'], + uid: ['0'], + owner: ['root'], + gid: ['0'], + group: ['root'], + mode: ['0666'], + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + + user: { name: ['root'] }, + process: { + pid: [27244], + name: ['systemd-journal'], + ppid: [1], + executable: ['/lib/systemd/systemd-journald'], + title: ['/lib/systemd/systemd-journald'], + working_directory: ['/'], + }, + }, + }, + { + _id: '29', + data: [ + { field: '@timestamp', value: ['2019-04-08T21:18:57.000Z'] }, + { field: 'event.action', value: ['user_login'] }, + { field: 'event.category', value: null }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'user.name', value: ['Braden'] }, + ], + ecs: { + _id: '29', + event: { + action: ['user_login'], + dataset: ['login'], + kind: ['event'], + module: ['system'], + outcome: ['failure'], + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + source: { + ip: ['128.199.212.120'], + }, + user: { + name: ['Braden'], + }, + process: { + pid: [6278], + }, + }, + }, + { + _id: '30', + data: [ + { field: '@timestamp', value: ['2019-04-08T22:27:14.814Z'] }, + { field: 'event.action', value: ['process_started'] }, + { field: 'event.category', value: null }, + { field: 'host.name', value: ['zeek-london'] }, + { field: 'user.name', value: ['Evan'] }, + ], + ecs: { + _id: '30', + event: { + action: ['process_started'], + dataset: ['login'], + kind: ['event'], + module: ['system'], + outcome: ['failure'], + }, + host: { + id: ['7c21f5ed03b04d0299569d221fe18bbc'], + name: ['zeek-london'], + ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], + }, + source: { + ip: ['128.199.212.120'], + }, + user: { + name: ['Evan'], + }, + process: { + pid: [6278], + }, + }, + }, + { + _id: '31', + data: [ + { field: '@timestamp', value: ['2018-11-05T19:03:25.937Z'] }, + { field: 'message', value: ['I am a log file message'] }, + { field: 'event.severity', value: ['3'] }, + { field: 'event.category', value: ['Access'] }, + { field: 'event.action', value: ['Action'] }, + { field: 'host.name', value: ['apache'] }, + { field: 'source.ip', value: ['192.168.0.1'] }, + { field: 'destination.ip', value: ['192.168.0.3'] }, + { field: 'destination.bytes', value: ['123456'] }, + { field: 'user.name', value: ['john.dee'] }, + ], + ecs: { + _id: '1', + timestamp: '2018-11-05T19:03:25.937Z', + host: { name: ['apache'], ip: ['192.168.0.1'] }, + event: { + id: ['1'], + action: ['Action'], + category: ['Access'], + module: ['nginx'], + severity: [3], + }, + message: ['I am a log file message'], + source: { ip: ['192.168.0.1'], port: [80] }, + destination: { ip: ['192.168.0.3'], port: [6343] }, + user: { id: ['1'], name: ['john.dee'] }, + geo: { region_name: ['xx'], country_iso_code: ['xx'] }, + }, + }, + { + _id: '32', + data: [], + ecs: { + _id: 'BuBP4W0BOpWiDweSoYSg', + timestamp: '2019-10-18T23:59:15.091Z', + threat: { + enrichments: [ + { + indicator: { + provider: ['indicator_provider'], + reference: ['https://example.com'], + }, + matched: { + atomic: ['192.168.1.1'], + field: ['source.ip'], + type: ['ip'], + }, + feed: { + name: ['feed_name'], + }, + }, + ], + }, + }, + }, +]; diff --git a/x-pack/plugins/security_solution/public/common/mock/mock_endgame_ecs_data.ts b/x-pack/plugins/security_solution/public/common/mock/mock_endgame_ecs_data.ts index 28be68fb6af63a..b7a9e0cd4593a8 100644 --- a/x-pack/plugins/security_solution/public/common/mock/mock_endgame_ecs_data.ts +++ b/x-pack/plugins/security_solution/public/common/mock/mock_endgame_ecs_data.ts @@ -7,56 +7,17 @@ import type { Ecs } from '../../../common/ecs'; -export const mockEndgameDnsRequest: Ecs = { - _id: 'S8jPcG0BOpWiDweSou3g', - user: { - id: ['S-1-5-18'], - domain: ['NT AUTHORITY'], - name: ['SYSTEM'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['6.1'], - }, - ip: ['10.178.85.222'], - name: ['HD-obe-8bf77f54'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['request_event'], - category: ['network'], - kind: ['event'], - }, - message: [ - 'DNS query is completed for the name %1, type %2, query options %3 with status %4 Results %5 ', - ], - timestamp: '1569555712000', - dns: { - question: { - name: ['update.googleapis.com'], - type: ['A'], - }, - resolved_ip: ['10.100.197.67'], - }, - network: { - protocol: ['dns'], - }, - process: { - pid: [443192], - name: ['GoogleUpdate.exe'], - executable: ['C:\\Program Files (x86)\\Google\\Update\\GoogleUpdate.exe'], - }, - winlog: { - event_id: [3008], - }, - endgame: { - process_name: ['GoogleUpdate.exe'], - pid: [443192], - }, -}; +// these "mocks" are used by browser bundles so they were moved out of the mocks and are +// re-exported here for convenience and internal bwc +export { demoEndgameCreationEvent as mockEndgameCreationEvent } from '../demo_data/endgame_ecs/creation'; +export { demoEndgameDnsRequest as mockEndgameDnsRequest } from '../demo_data/endgame_ecs/dns'; +export { + demoEndgameFileCreateEvent as mockEndgameFileCreateEvent, + demoEndgameFileDeleteEvent as mockEndgameFileDeleteEvent, +} from '../demo_data/endgame_ecs/file_events'; +export { demoEndgameIpv4ConnectionAcceptEvent as mockEndgameIpv4ConnectionAcceptEvent } from '../demo_data/endgame_ecs/ipv4'; +export { demoEndgameTerminationEvent as mockEndgameTerminationEvent } from '../demo_data/endgame_ecs/termination'; +export { demoEndgameUserLogon as mockEndgameUserLogon } from '../demo_data/endgame_ecs/user_logon'; export const mockEndpointNetworkLookupRequestedEvent: Ecs = { host: { @@ -173,39 +134,6 @@ export const mockEndpointNetworkLookupResultEvent: Ecs = { _id: 'skNzOncBPmkOXwyN9VbT', }; -export const mockEndgameFileCreateEvent: Ecs = { - _id: '98jPcG0BOpWiDweSouzg', - user: { - id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], - domain: ['Anvi-Acer'], - name: ['Arun'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['6.1'], - }, - ip: ['10.178.85.222'], - name: ['HD-obe-8bf77f54'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['file_create_event'], - category: ['file'], - kind: ['event'], - }, - timestamp: '1569555712000', - endgame: { - process_name: ['chrome.exe'], - pid: [11620], - file_path: [ - 'C:\\Users\\Arun\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\63d78c21-e593-4484-b7a9-db33cd522ddc.tmp', - ], - }, -}; - export const mockEndpointFileCreationEvent: Ecs = { file: { path: ['C:\\Windows\\TEMP\\E38FD162-B6E6-4799-B52D-F590BACBAE94\\WimProvider.dll'], @@ -259,38 +187,6 @@ export const mockEndpointFileCreationEvent: Ecs = { _id: 'eSdbOncBLJMagDUQ3YFs', }; -export const mockEndgameFileDeleteEvent: Ecs = { - _id: 'OMjPcG0BOpWiDweSeuW9', - user: { - id: ['S-1-5-18'], - domain: ['NT AUTHORITY'], - name: ['SYSTEM'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['10.0'], - }, - ip: ['10.134.159.150'], - name: ['HD-v1s-d2118419'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['file_delete_event'], - category: ['file'], - kind: ['event'], - }, - timestamp: '1569555704000', - endgame: { - pid: [1084], - file_name: ['tmp000002f6'], - file_path: ['C:\\Windows\\TEMP\\tmp00000404\\tmp000002f6'], - process_name: ['AmSvc.exe'], - }, -}; - export const mockEndpointFileDeletionEvent: Ecs = { file: { path: ['C:\\Windows\\SoftwareDistribution\\Download\\Install\\AM_Delta_Patch_1.329.2793.0.exe'], @@ -1222,52 +1118,6 @@ export const mockEndpointProcessForkEvent: Ecs = { _id: 'KXomX3cBGrBB52F2S9XY', }; -export const mockEndgameIpv4ConnectionAcceptEvent: Ecs = { - _id: 'LsjPcG0BOpWiDweSCNfu', - user: { - id: ['S-1-5-18'], - domain: ['NT AUTHORITY'], - name: ['SYSTEM'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['10.0'], - }, - ip: ['10.43.255.177'], - name: ['HD-gqf-0af7b4fe'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['ipv4_connection_accept_event'], - category: ['network'], - kind: ['event'], - }, - timestamp: '1569555676000', - network: { - community_id: ['1:network-community_id'], - transport: ['tcp'], - }, - process: { - pid: [1084], - name: ['AmSvc.exe'], - executable: ['C:\\Program Files\\Cybereason ActiveProbe\\AmSvc.exe'], - }, - source: { - ip: ['127.0.0.1'], - port: [49306], - }, - destination: { - port: [49305], - ip: ['127.0.0.1'], - }, - endgame: { - pid: [1084], - }, -}; - export const mockEndgameIpv6ConnectionAcceptEvent: Ecs = { _id: '-8SucG0BOpWiDweS0wrq', user: { @@ -1545,54 +1395,6 @@ export const mockEndpointDisconnectReceivedEvent: Ecs = { _id: 'uUN0OncBPmkOXwyNOGPV', }; -export const mockEndgameUserLogon: Ecs = { - _id: 'QsjPcG0BOpWiDweSeuRE', - user: { - id: ['S-1-5-18'], - domain: ['NT AUTHORITY'], - name: ['SYSTEM'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['10.0'], - }, - ip: ['10.134.159.150'], - name: ['HD-v1s-d2118419'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['user_logon'], - category: ['authentication'], - type: ['authentication_success'], - kind: ['event'], - }, - message: [ - 'An account was successfully logged on.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tWIN-Q3DOP1UKA81$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3e7\r\n\r\nLogon Type:\t\t\t5\r\n\r\nNew Logon:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3e7\r\n\tLogon GUID:\t\t{00000000-0000-0000-0000-000000000000}\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x1b0\r\n\tProcess Name:\t\tC:\\Windows\\System32\\services.exe\r\n\r\nNetwork Information:\r\n\tWorkstation Name:\t\r\n\tSource Network Address:\t-\r\n\tSource Port:\t\t-\r\n\r\nDetailed Authentication Information:\r\n\tLogon Process:\t\tAdvapi \r\n\tAuthentication Package:\tNegotiate\r\n\tTransited Services:\t-\r\n\tPackage Name (NTLM only):\t-\r\n\tKey Length:\t\t0\r\n\r\nThis event is generated when a logon session is created. It is generated on the computer that was accessed.\r\n\r\nThe subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.\r\n\r\nThe logon type field indicates the kind of logon that occurred. The most common types are 2 (interactive) and 3 (network).\r\n\r\nThe New Logon fields indicate the account for whom the new logon was created, i.e. the account that was logged on.\r\n\r\nThe network fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.\r\n\r\nThe authentication information fields provide detailed information about this specific logon request.\r\n\t- Logon GUID is a unique identifier that can be used to correlate this event with a KDC event.\r\n\t- Transited services indicate which intermediate services have participated in this logon request.\r\n\t- Package name indicates which sub-protocol was used among the NTLM protocols.\r\n\t- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.', - ], - timestamp: '1569555704000', - process: { - pid: [432], - name: ['C:\\Windows\\System32\\services.exe'], - executable: ['C:\\Windows\\System32\\services.exe'], - }, - winlog: { - event_id: [4624], - }, - endgame: { - target_logon_id: ['0x3e7'], - pid: [432], - process_name: ['C:\\Windows\\System32\\services.exe'], - logon_type: [5], - subject_user_name: ['WIN-Q3DOP1UKA81$'], - subject_logon_id: ['0x3e7'], - target_user_name: ['SYSTEM'], - target_domain_name: ['NT AUTHORITY'], - }, -}; - export const mockEndpointSecurityLogOnSuccessEvent: Ecs = { host: { os: { @@ -1853,55 +1655,6 @@ export const mockEndpointSecurityLogOffEvent: Ecs = { _id: 'ZesLQXcBPmkOXwyNdT1a', }; -export const mockEndgameCreationEvent: Ecs = { - _id: 'BcjPcG0BOpWiDweSou3g', - user: { - id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], - domain: ['Anvi-Acer'], - name: ['Arun'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['6.1'], - }, - ip: ['10.178.85.222'], - name: ['HD-obe-8bf77f54'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['creation_event'], - category: ['process'], - type: ['process_start'], - kind: ['event'], - }, - timestamp: '1569555712000', - process: { - hash: { - md5: ['62d06d7235b37895b68de56687895743'], - sha1: ['12563599116157778a22600d2a163d8112aed845'], - sha256: ['d4c97ed46046893141652e2ec0056a698f6445109949d7fcabbce331146889ee'], - }, - pid: [441684], - ppid: [8], - name: ['Microsoft.Photos.exe'], - executable: [ - 'C:\\Program Files\\WindowsApps\\Microsoft.Windows.Photos_2018.18091.17210.0_x64__8wekyb3d8bbwe\\Microsoft.Photos.exe', - ], - args: [ - 'C:\\Program Files\\WindowsApps\\Microsoft.Windows.Photos_2018.18091.17210.0_x64__8wekyb3d8bbwe\\Microsoft.Photos.exe', - '-ServerName:App.AppXzst44mncqdg84v7sv6p7yznqwssy6f7f.mca', - ], - }, - endgame: { - process_name: ['Microsoft.Photos.exe'], - pid: [441684], - parent_process_name: ['svchost.exe'], - }, -}; - export const mockEndpointProcessStartEvent: Ecs = { process: { hash: { @@ -1954,48 +1707,6 @@ export const mockEndpointProcessStartEvent: Ecs = { _id: 't5KSO3cB8l64wN2iQ8V9', }; -export const mockEndgameTerminationEvent: Ecs = { - _id: '2MjPcG0BOpWiDweSoutC', - user: { - id: ['S-1-5-21-3573271228-3407584681-1597858646-1002'], - domain: ['Anvi-Acer'], - name: ['Arun'], - }, - host: { - os: { - platform: ['windows'], - name: ['Windows'], - version: ['6.1'], - }, - ip: ['10.178.85.222'], - name: ['HD-obe-8bf77f54'], - }, - event: { - module: ['endgame'], - dataset: ['esensor'], - action: ['termination_event'], - category: ['process'], - kind: ['event'], - }, - timestamp: '1569555712000', - process: { - hash: { - md5: ['bd4401441a21bf1abce6404f4231db4d'], - sha1: ['797255e72d5ed5c058d4785950eba7abaa057653'], - sha256: ['87976f3430cc99bc939e0694247c0759961a49832b87218f4313d6fc0bc3a776'], - }, - pid: [442384], - ppid: [8], - name: ['RuntimeBroker.exe'], - executable: ['C:\\Windows\\System32\\RuntimeBroker.exe'], - }, - endgame: { - pid: [442384], - process_name: ['RuntimeBroker.exe'], - exit_code: [0], - }, -}; - export const mockEndpointProcessEndEvent: Ecs = { process: { hash: { diff --git a/x-pack/plugins/security_solution/public/common/mock/mock_timeline_data.ts b/x-pack/plugins/security_solution/public/common/mock/mock_timeline_data.ts index bcc024ad057fde..3ba5aab6a6dd87 100644 --- a/x-pack/plugins/security_solution/public/common/mock/mock_timeline_data.ts +++ b/x-pack/plugins/security_solution/public/common/mock/mock_timeline_data.ts @@ -6,1116 +6,11 @@ */ import type { Ecs } from '../../../common/ecs'; -import type { TimelineItem } from '../../../common/search_strategy/timeline'; -export const mockTimelineData: TimelineItem[] = [ - { - _id: '1', - data: [ - { field: '@timestamp', value: ['2018-11-05T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'event.action', value: ['Action'] }, - { field: 'host.name', value: ['apache'] }, - { field: 'source.ip', value: ['192.168.0.1'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['john.dee'] }, - ], - ecs: { - _id: '1', - timestamp: '2018-11-05T19:03:25.937Z', - host: { name: ['apache'], ip: ['192.168.0.1'] }, - event: { - id: ['1'], - action: ['Action'], - category: ['Access'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.1'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['1'], name: ['john.dee'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '3', - data: [ - { field: '@timestamp', value: ['2018-11-07T19:03:25.937Z'] }, - { field: 'event.severity', value: ['1'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['nginx'] }, - { field: 'source.ip', value: ['192.168.0.3'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['evan.davis'] }, - ], - ecs: { - _id: '3', - timestamp: '2018-11-07T19:03:25.937Z', - host: { name: ['nginx'], ip: ['192.168.0.1'] }, - event: { - id: ['3'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [1], - }, - source: { ip: ['192.168.0.3'], port: [443] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['3'], name: ['evan.davis'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '4', - data: [ - { field: '@timestamp', value: ['2018-11-08T19:03:25.937Z'] }, - { field: 'event.severity', value: ['1'] }, - { field: 'event.category', value: ['Attempted Administrator Privilege Gain'] }, - { field: 'host.name', value: ['suricata'] }, - { field: 'source.ip', value: ['192.168.0.3'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jenny.jones'] }, - ], - ecs: { - _id: '4', - timestamp: '2018-11-08T19:03:25.937Z', - host: { name: ['suricata'], ip: ['192.168.0.1'] }, - event: { - id: ['4'], - category: ['Attempted Administrator Privilege Gain'], - type: ['Alert'], - module: ['suricata'], - severity: [1], - }, - source: { ip: ['192.168.0.3'], port: [53] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - suricata: { - eve: { - flow_id: [4], - proto: [''], - alert: { - signature: [ - 'ET EXPLOIT NETGEAR WNR2000v5 hidden_lang_avi Stack Overflow (CVE-2016-10174)', - ], - signature_id: [4], - }, - }, - }, - user: { id: ['4'], name: ['jenny.jones'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '5', - data: [ - { field: '@timestamp', value: ['2018-11-09T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.3'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['becky.davis'] }, - ], - ecs: { - _id: '5', - timestamp: '2018-11-09T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['5'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.3'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['5'], name: ['becky.davis'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '6', - data: [ - { field: '@timestamp', value: ['2018-11-10T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['braden.davis'] }, - { field: 'source.ip', value: ['192.168.0.6'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - ], - ecs: { - _id: '6', - timestamp: '2018-11-10T19:03:25.937Z', - host: { name: ['braden.davis'], ip: ['192.168.0.1'] }, - event: { - id: ['6'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.6'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '8', - data: [ - { field: '@timestamp', value: ['2018-11-12T19:03:25.937Z'] }, - { field: 'event.severity', value: ['2'] }, - { field: 'event.category', value: ['Web Application Attack'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.8'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '8', - timestamp: '2018-11-12T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['8'], - category: ['Web Application Attack'], - type: ['Alert'], - module: ['suricata'], - severity: [2], - }, - suricata: { - eve: { - flow_id: [8], - proto: [''], - alert: { - signature: ['ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Cookie'], - signature_id: [8], - }, - }, - }, - source: { ip: ['192.168.0.8'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['8'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '7', - data: [ - { field: '@timestamp', value: ['2018-11-11T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.7'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '7', - timestamp: '2018-11-11T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['7'], - category: ['Access'], - type: ['HTTP Request'], - module: ['apache'], - severity: [3], - }, - source: { ip: ['192.168.0.7'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['7'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '9', - data: [ - { field: '@timestamp', value: ['2018-11-13T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.9'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '9', - timestamp: '2018-11-13T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['9'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.9'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['9'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '10', - data: [ - { field: '@timestamp', value: ['2018-11-14T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.10'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '10', - timestamp: '2018-11-14T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['10'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.10'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['10'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '11', - data: [ - { field: '@timestamp', value: ['2018-11-15T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.11'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '11', - timestamp: '2018-11-15T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['11'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.11'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['11'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '12', - data: [ - { field: '@timestamp', value: ['2018-11-16T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.12'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['jone.doe'] }, - ], - ecs: { - _id: '12', - timestamp: '2018-11-16T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['12'], - category: ['Access'], - type: ['HTTP Request'], - module: ['nginx'], - severity: [3], - }, - source: { ip: ['192.168.0.12'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['12'], name: ['jone.doe'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '2', - data: [ - { field: '@timestamp', value: ['2018-11-06T19:03:25.937Z'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Authentication'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.2'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['joe.bob'] }, - ], - ecs: { - _id: '2', - timestamp: '2018-11-06T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['2'], - category: ['Authentication'], - type: ['Authentication Success'], - module: ['authlog'], - severity: [3], - }, - source: { ip: ['192.168.0.2'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['1'], name: ['joe.bob'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '13', - data: [ - { field: '@timestamp', value: ['2018-13-12T19:03:25.937Z'] }, - { field: 'event.severity', value: ['1'] }, - { field: 'event.category', value: ['Web Application Attack'] }, - { field: 'host.name', value: ['joe.computer'] }, - { field: 'source.ip', value: ['192.168.0.8'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - ], - ecs: { - _id: '13', - timestamp: '2018-13-12T19:03:25.937Z', - host: { name: ['joe.computer'], ip: ['192.168.0.1'] }, - event: { - id: ['13'], - category: ['Web Application Attack'], - type: ['Alert'], - module: ['suricata'], - severity: [1], - }, - suricata: { - eve: { - flow_id: [13], - proto: [''], - alert: { - signature: ['ET WEB_SERVER Possible Attempt in HTTP Cookie'], - signature_id: [13], - }, - }, - }, - source: { ip: ['192.168.0.8'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '14', - data: [ - { field: '@timestamp', value: ['2019-03-07T05:06:51.000Z'] }, - { field: 'host.name', value: ['zeek-franfurt'] }, - { field: 'source.ip', value: ['192.168.26.101'] }, - { field: 'destination.ip', value: ['192.168.238.205'] }, - ], - ecs: { - _id: '14', - timestamp: '2019-03-07T05:06:51.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.connection'], - }, - host: { - id: ['37c81253e0fc4c46839c19b981be5177'], - name: ['zeek-franfurt'], - ip: ['207.154.238.205', '10.19.0.5', 'fe80::d82b:9aff:fe0d:1e12'], - }, - source: { ip: ['185.176.26.101'], port: [44059] }, - destination: { ip: ['207.154.238.205'], port: [11568] }, - geo: { region_name: ['New York'], country_iso_code: ['US'] }, - network: { transport: ['tcp'] }, - zeek: { - session_id: ['C8DRTq362Fios6hw16'], - connection: { - local_resp: [false], - local_orig: [false], - missed_bytes: [0], - state: ['REJ'], - history: ['Sr'], - }, - }, - }, - }, - { - _id: '15', - data: [ - { field: '@timestamp', value: ['2019-03-07T00:51:28.000Z'] }, - { field: 'host.name', value: ['suricata-zeek-singapore'] }, - { field: 'source.ip', value: ['192.168.35.240'] }, - { field: 'destination.ip', value: ['192.168.67.3'] }, - ], - ecs: { - _id: '15', - timestamp: '2019-03-07T00:51:28.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.dns'], - }, - host: { - id: ['af3fddf15f1d47979ce817ba0df10c6e'], - name: ['suricata-zeek-singapore'], - ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], - }, - source: { ip: ['206.189.35.240'], port: [57475] }, - destination: { ip: ['67.207.67.3'], port: [53] }, - geo: { region_name: ['New York'], country_iso_code: ['US'] }, - network: { transport: ['udp'] }, - zeek: { - session_id: ['CyIrMA1L1JtLqdIuol'], - dns: { - AA: [false], - RD: [false], - trans_id: [65252], - RA: [false], - TC: [false], - }, - }, - }, - }, - { - _id: '16', - data: [ - { field: '@timestamp', value: ['2019-03-05T07:00:20.000Z'] }, - { field: 'host.name', value: ['suricata-zeek-singapore'] }, - { field: 'source.ip', value: ['192.168.35.240'] }, - { field: 'destination.ip', value: ['192.168.164.26'] }, - ], - ecs: { - _id: '16', - timestamp: '2019-03-05T07:00:20.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.http'], - }, - host: { - id: ['af3fddf15f1d47979ce817ba0df10c6e'], - name: ['suricata-zeek-singapore'], - ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], - }, - source: { ip: ['206.189.35.240'], port: [36220] }, - destination: { ip: ['192.241.164.26'], port: [80] }, - geo: { region_name: ['New York'], country_iso_code: ['US'] }, - http: { - version: ['1.1'], - request: { body: { bytes: [0] } }, - response: { status_code: [302], body: { bytes: [154] } }, - }, - zeek: { - session_id: ['CZLkpC22NquQJOpkwe'], - - http: { - resp_mime_types: ['text/html'], - trans_depth: ['3'], - status_msg: ['Moved Temporarily'], - resp_fuids: ['FzeujEPP7GTHmYPsc'], - tags: [], - }, - }, - }, - }, - { - _id: '17', - data: [ - { field: '@timestamp', value: ['2019-02-28T22:36:28.000Z'] }, - { field: 'host.name', value: ['zeek-franfurt'] }, - { field: 'source.ip', value: ['192.168.77.171'] }, - ], - ecs: { - _id: '17', - timestamp: '2019-02-28T22:36:28.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.notice'], - }, - host: { - id: ['37c81253e0fc4c46839c19b981be5177'], - name: ['zeek-franfurt'], - ip: ['207.154.238.205', '10.19.0.5', 'fe80::d82b:9aff:fe0d:1e12'], - }, - source: { ip: ['8.42.77.171'] }, - zeek: { - notice: { - suppress_for: [3600], - msg: ['8.42.77.171 scanned at least 15 unique ports of host 207.154.238.205 in 0m0s'], - note: ['Scan::Port_Scan'], - sub: ['remote'], - dst: ['207.154.238.205'], - dropped: [false], - peer_descr: ['bro'], - }, - }, - }, - }, - { - _id: '18', - data: [ - { field: '@timestamp', value: ['2019-02-22T21:12:13.000Z'] }, - { field: 'host.name', value: ['zeek-sensor-amsterdam'] }, - { field: 'source.ip', value: ['192.168.66.184'] }, - { field: 'destination.ip', value: ['192.168.95.15'] }, - ], - ecs: { - _id: '18', - timestamp: '2019-02-22T21:12:13.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.ssl'], - }, - host: { id: ['2ce8b1e7d69e4a1d9c6bcddc473da9d9'], name: ['zeek-sensor-amsterdam'] }, - source: { ip: ['188.166.66.184'], port: [34514] }, - destination: { ip: ['91.189.95.15'], port: [443] }, - geo: { region_name: ['England'], country_iso_code: ['GB'] }, - zeek: { - session_id: ['CmTxzt2OVXZLkGDaRe'], - ssl: { - cipher: ['TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'], - established: [false], - resumed: [false], - version: ['TLSv12'], - }, - }, - }, - }, - { - _id: '19', - data: [ - { field: '@timestamp', value: ['2019-03-03T04:26:38.000Z'] }, - { field: 'host.name', value: ['suricata-zeek-singapore'] }, - ], - ecs: { - _id: '19', - timestamp: '2019-03-03T04:26:38.000Z', - event: { - module: ['zeek'], - dataset: ['zeek.files'], - }, - host: { - id: ['af3fddf15f1d47979ce817ba0df10c6e'], - name: ['suricata-zeek-singapore'], - ip: ['206.189.35.240', '10.15.0.5', 'fe80::98c7:eff:fe29:4455'], - }, - zeek: { - session_id: ['Cu0n232QMyvNtzb75j'], - files: { - session_ids: ['Cu0n232QMyvNtzb75j'], - timedout: [false], - local_orig: [false], - tx_host: ['5.101.111.50'], - source: ['HTTP'], - is_orig: [false], - overflow_bytes: [0], - sha1: ['fa5195a5dfacc9d1c68d43600f0e0262cad14dde'], - duration: [0], - depth: [0], - analyzers: ['MD5', 'SHA1'], - mime_type: ['text/plain'], - rx_host: ['206.189.35.240'], - total_bytes: [88722], - fuid: ['FePz1uVEVCZ3I0FQi'], - seen_bytes: [1198], - missing_bytes: [0], - md5: ['f7653f1951693021daa9e6be61226e32'], - }, - }, - }, - }, - { - _id: '20', - data: [ - { field: '@timestamp', value: ['2019-03-13T05:42:11.815Z'] }, - { field: 'event.category', value: ['audit-rule'] }, - { field: 'host.name', value: ['zeek-sanfran'] }, - { field: 'process.args', value: ['gpgconf', '--list-dirs', 'agent-socket'] }, - ], - ecs: { - _id: '20', - timestamp: '2019-03-13T05:42:11.815Z', - event: { - action: ['executed'], - module: ['auditd'], - category: ['audit-rule'], - }, - host: { - id: ['f896741c3b3b44bdb8e351a4ab6d2d7c'], - name: ['zeek-sanfran'], - ip: ['134.209.63.134', '10.46.0.5', 'fe80::a0d9:16ff:fecf:e70b'], - }, - user: { name: ['alice'] }, - process: { - pid: [5402], - name: ['gpgconf'], - ppid: [5401], - args: ['gpgconf', '--list-dirs', 'agent-socket'], - executable: ['/usr/bin/gpgconf'], - title: ['gpgconf --list-dirs agent-socket'], - working_directory: ['/'], - }, - }, - }, - { - _id: '21', - data: [ - { field: '@timestamp', value: ['2019-03-14T22:30:25.527Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'source.ip', value: ['192.168.77.171'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '21', - timestamp: '2019-03-14T22:30:25.527Z', - event: { - action: ['logged-in'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['14'], - data: { terminal: ['/dev/pts/0'], op: ['login'] }, - summary: { - actor: { primary: ['alice'], secondary: ['alice'] }, - object: { primary: ['/dev/pts/0'], secondary: ['8.42.77.171'], type: ['user-session'] }, - how: ['/usr/sbin/sshd'], - }, - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - source: { ip: ['8.42.77.171'] }, - user: { name: ['root'] }, - process: { - pid: [17471], - executable: ['/usr/sbin/sshd'], - }, - }, - }, - { - _id: '22', - data: [ - { field: '@timestamp', value: ['2019-03-13T03:35:21.614Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['suricata-bangalore'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '22', - timestamp: '2019-03-13T03:35:21.614Z', - event: { - action: ['disposed-credentials'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['340'], - data: { acct: ['alice'], terminal: ['ssh'], op: ['PAM:setcred'] }, - summary: { - actor: { primary: ['alice'], secondary: ['alice'] }, - object: { primary: ['ssh'], secondary: ['8.42.77.171'], type: ['user-session'] }, - how: ['/usr/sbin/sshd'], - }, - }, - host: { - id: ['0a63559c1acf4c419d979c4b4d8b83ff'], - name: ['suricata-bangalore'], - ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], - }, - user: { name: ['root'] }, - process: { - pid: [21202], - executable: ['/usr/sbin/sshd'], - }, - }, - }, - { - _id: '23', - data: [ - { field: '@timestamp', value: ['2019-03-13T03:35:21.614Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['suricata-bangalore'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '23', - timestamp: '2019-03-13T03:35:21.614Z', - event: { - action: ['ended-session'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['340'], - data: { acct: ['alice'], terminal: ['ssh'], op: ['PAM:session_close'] }, - summary: { - actor: { primary: ['alice'], secondary: ['alice'] }, - object: { primary: ['ssh'], secondary: ['8.42.77.171'], type: ['user-session'] }, - how: ['/usr/sbin/sshd'], - }, - }, - host: { - id: ['0a63559c1acf4c419d979c4b4d8b83ff'], - name: ['suricata-bangalore'], - ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], - }, - user: { name: ['root'] }, - process: { - pid: [21202], - executable: ['/usr/sbin/sshd'], - }, - }, - }, - { - _id: '24', - data: [ - { field: '@timestamp', value: ['2019-03-18T23:17:01.645Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '24', - timestamp: '2019-03-18T23:17:01.645Z', - event: { - action: ['acquired-credentials'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['unset'], - data: { acct: ['root'], terminal: ['cron'], op: ['PAM:setcred'] }, - summary: { - actor: { primary: ['unset'], secondary: ['root'] }, - object: { primary: ['cron'], type: ['user-session'] }, - how: ['/usr/sbin/cron'], - }, - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - user: { name: ['root'] }, - process: { - pid: [9592], - executable: ['/usr/sbin/cron'], - }, - }, - }, - { - _id: '25', - data: [ - { field: '@timestamp', value: ['2019-03-19T01:17:01.336Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['siem-kibana'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '25', - timestamp: '2019-03-19T01:17:01.336Z', - event: { - action: ['started-session'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['2908'], - data: { acct: ['root'], terminal: ['cron'], op: ['PAM:session_open'] }, - summary: { - actor: { primary: ['root'], secondary: ['root'] }, - object: { primary: ['cron'], type: ['user-session'] }, - how: ['/usr/sbin/cron'], - }, - }, - host: { id: ['aa7ca589f1b8220002f2fc61c64cfbf1'], name: ['siem-kibana'] }, - user: { name: ['root'] }, - process: { - pid: [725], - executable: ['/usr/sbin/cron'], - }, - }, - }, - { - _id: '26', - data: [ - { field: '@timestamp', value: ['2019-03-13T03:34:08.890Z'] }, - { field: 'event.category', value: ['user-login'] }, - { field: 'host.name', value: ['suricata-bangalore'] }, - { field: 'user.name', value: ['alice'] }, - ], - ecs: { - _id: '26', - timestamp: '2019-03-13T03:34:08.890Z', - event: { - action: ['was-authorized'], - module: ['auditd'], - category: ['user-login'], - }, - auditd: { - result: ['success'], - session: ['338'], - data: { terminal: ['/dev/pts/0'] }, - summary: { - actor: { primary: ['root'], secondary: ['alice'] }, - object: { primary: ['/dev/pts/0'], type: ['user-session'] }, - how: ['/sbin/pam_tally2'], - }, - }, - host: { - id: ['0a63559c1acf4c419d979c4b4d8b83ff'], - name: ['suricata-bangalore'], - ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'], - }, - user: { name: ['alice'] }, - process: { - pid: [21170], - executable: ['/sbin/pam_tally2'], - }, - }, - }, - { - _id: '27', - data: [ - { field: '@timestamp', value: ['2019-03-22T19:13:11.026Z'] }, - { field: 'event.action', value: ['connected-to'] }, - { field: 'event.category', value: ['audit-rule'] }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'destination.ip', value: ['192.168.216.34'] }, - { field: 'user.name', value: ['alice'] }, - ], - ecs: { - _id: '27', - timestamp: '2019-03-22T19:13:11.026Z', - event: { - action: ['connected-to'], - module: ['auditd'], - category: ['audit-rule'], - }, - auditd: { - result: ['success'], - session: ['246'], - summary: { - actor: { primary: ['alice'], secondary: ['alice'] }, - object: { primary: ['192.168.216.34'], secondary: ['80'], type: ['socket'] }, - how: ['/usr/bin/wget'], - }, - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - destination: { ip: ['192.168.216.34'], port: [80] }, - user: { name: ['alice'] }, - process: { - pid: [1490], - name: ['wget'], - ppid: [1476], - executable: ['/usr/bin/wget'], - title: ['wget www.example.com'], - }, - }, - }, - { - _id: '28', - data: [ - { field: '@timestamp', value: ['2019-03-26T22:12:18.609Z'] }, - { field: 'event.action', value: ['opened-file'] }, - { field: 'event.category', value: ['audit-rule'] }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'user.name', value: ['root'] }, - ], - ecs: { - _id: '28', - timestamp: '2019-03-26T22:12:18.609Z', - event: { - action: ['opened-file'], - module: ['auditd'], - category: ['audit-rule'], - }, - auditd: { - result: ['success'], - session: ['242'], - summary: { - actor: { primary: ['unset'], secondary: ['root'] }, - object: { primary: ['/proc/15990/attr/current'], type: ['file'] }, - how: ['/lib/systemd/systemd-journald'], - }, - }, - file: { - path: ['/proc/15990/attr/current'], - device: ['00:00'], - inode: ['27672309'], - uid: ['0'], - owner: ['root'], - gid: ['0'], - group: ['root'], - mode: ['0666'], - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - - user: { name: ['root'] }, - process: { - pid: [27244], - name: ['systemd-journal'], - ppid: [1], - executable: ['/lib/systemd/systemd-journald'], - title: ['/lib/systemd/systemd-journald'], - working_directory: ['/'], - }, - }, - }, - { - _id: '29', - data: [ - { field: '@timestamp', value: ['2019-04-08T21:18:57.000Z'] }, - { field: 'event.action', value: ['user_login'] }, - { field: 'event.category', value: null }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'user.name', value: ['Braden'] }, - ], - ecs: { - _id: '29', - event: { - action: ['user_login'], - dataset: ['login'], - kind: ['event'], - module: ['system'], - outcome: ['failure'], - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - source: { - ip: ['128.199.212.120'], - }, - user: { - name: ['Braden'], - }, - process: { - pid: [6278], - }, - }, - }, - { - _id: '30', - data: [ - { field: '@timestamp', value: ['2019-04-08T22:27:14.814Z'] }, - { field: 'event.action', value: ['process_started'] }, - { field: 'event.category', value: null }, - { field: 'host.name', value: ['zeek-london'] }, - { field: 'user.name', value: ['Evan'] }, - ], - ecs: { - _id: '30', - event: { - action: ['process_started'], - dataset: ['login'], - kind: ['event'], - module: ['system'], - outcome: ['failure'], - }, - host: { - id: ['7c21f5ed03b04d0299569d221fe18bbc'], - name: ['zeek-london'], - ip: ['46.101.3.136', '10.16.0.5', 'fe80::4066:42ff:fe19:b3b9'], - }, - source: { - ip: ['128.199.212.120'], - }, - user: { - name: ['Evan'], - }, - process: { - pid: [6278], - }, - }, - }, - { - _id: '31', - data: [ - { field: '@timestamp', value: ['2018-11-05T19:03:25.937Z'] }, - { field: 'message', value: ['I am a log file message'] }, - { field: 'event.severity', value: ['3'] }, - { field: 'event.category', value: ['Access'] }, - { field: 'event.action', value: ['Action'] }, - { field: 'host.name', value: ['apache'] }, - { field: 'source.ip', value: ['192.168.0.1'] }, - { field: 'destination.ip', value: ['192.168.0.3'] }, - { field: 'destination.bytes', value: ['123456'] }, - { field: 'user.name', value: ['john.dee'] }, - ], - ecs: { - _id: '1', - timestamp: '2018-11-05T19:03:25.937Z', - host: { name: ['apache'], ip: ['192.168.0.1'] }, - event: { - id: ['1'], - action: ['Action'], - category: ['Access'], - module: ['nginx'], - severity: [3], - }, - message: ['I am a log file message'], - source: { ip: ['192.168.0.1'], port: [80] }, - destination: { ip: ['192.168.0.3'], port: [6343] }, - user: { id: ['1'], name: ['john.dee'] }, - geo: { region_name: ['xx'], country_iso_code: ['xx'] }, - }, - }, - { - _id: '32', - data: [], - ecs: { - _id: 'BuBP4W0BOpWiDweSoYSg', - timestamp: '2019-10-18T23:59:15.091Z', - threat: { - enrichments: [ - { - indicator: { - provider: ['indicator_provider'], - reference: ['https://example.com'], - }, - matched: { - atomic: ['192.168.1.1'], - field: ['source.ip'], - type: ['ip'], - }, - feed: { - name: ['feed_name'], - }, - }, - ], - }, - }, - }, -]; +export { demoTimelineData as mockTimelineData } from '../demo_data/timeline'; +export { demoEndpointRegistryModificationEvent as mockEndpointRegistryModificationEvent } from '../demo_data/endpoint/registry_modification_event'; +export { demoEndpointLibraryLoadEvent as mockEndpointLibraryLoadEvent } from '../demo_data/endpoint/library_load_event'; +export { demoEndpointProcessExecutionMalwarePreventionAlert as mockEndpointProcessExecutionMalwarePreventionAlert } from '../demo_data/endpoint/process_execution_malware_prevention_alert'; export const mockFimFileCreatedEvent: Ecs = { _id: 'WuBP4W0BOpWiDweSoYSg', @@ -1329,186 +224,3 @@ export const mockDnsEvent: Ecs = { ip: ['10.9.9.9'], }, }; - -export const mockEndpointProcessExecutionMalwarePreventionAlert: Ecs = { - process: { - hash: { - md5: ['177afc1eb0be88eb9983fb74111260c4'], - sha256: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb'], - sha1: ['f573b85e9beb32121f1949217947b2adc6749e3d'], - }, - entity_id: [ - 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTY5MjAtMTMyNDg5OTk2OTAuNDgzMzA3NzAw', - ], - executable: [ - 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', - ], - name: [ - 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', - ], - pid: [6920], - args: [ - 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', - ], - }, - host: { - os: { - full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1518)'], - name: ['Windows'], - version: ['1809 (10.0.17763.1518)'], - platform: ['windows'], - family: ['windows'], - kernel: ['1809 (10.0.17763.1518)'], - }, - mac: ['aa:bb:cc:dd:ee:ff'], - architecture: ['x86_64'], - ip: ['10.1.2.3'], - id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], - name: ['win2019-endpoint-1'], - }, - file: { - mtime: ['2020-11-04T21:40:51.494Z'], - path: [ - 'C:\\Users\\sean\\Downloads\\3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe', - ], - owner: ['sean'], - hash: { - md5: ['177afc1eb0be88eb9983fb74111260c4'], - sha256: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb'], - sha1: ['f573b85e9beb32121f1949217947b2adc6749e3d'], - }, - name: ['3be13acde2f4dcded4fd8d518a513bfc9882407a6e384ffb17d12710db7d76fb.exe'], - extension: ['exe'], - size: [1604112], - }, - event: { - category: ['malware', 'intrusion_detection', 'process'], - outcome: ['success'], - severity: [73], - code: ['malicious_file'], - action: ['execution'], - id: ['LsuMZVr+sdhvehVM++++Gp2Y'], - kind: ['alert'], - created: ['2020-11-04T21:41:30.533Z'], - module: ['endpoint'], - type: ['info', 'start', 'denied'], - dataset: ['endpoint.alerts'], - }, - agent: { - type: ['endpoint'], - }, - timestamp: '2020-11-04T21:41:30.533Z', - message: ['Malware Prevention Alert'], - _id: '0dA2lXUBn9bLIbfPkY7d', -}; - -export const mockEndpointLibraryLoadEvent: Ecs = { - file: { - path: ['C:\\Windows\\System32\\bcrypt.dll'], - hash: { - md5: ['00439016776de367bad087d739a03797'], - sha1: ['2c4ba5c1482987d50a182bad915f52cd6611ee63'], - sha256: ['e70f5d8f87aab14e3160227d38387889befbe37fa4f8f5adc59eff52804b35fd'], - }, - name: ['bcrypt.dll'], - }, - host: { - os: { - full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1697)'], - name: ['Windows'], - version: ['1809 (10.0.17763.1697)'], - family: ['windows'], - kernel: ['1809 (10.0.17763.1697)'], - platform: ['windows'], - }, - mac: ['aa:bb:cc:dd:ee:ff'], - name: ['win2019-endpoint-1'], - architecture: ['x86_64'], - ip: ['10.1.2.3'], - id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], - }, - event: { - category: ['library'], - kind: ['event'], - created: ['2021-02-05T21:27:23.921Z'], - module: ['endpoint'], - action: ['load'], - type: ['start'], - id: ['LzzWB9jjGmCwGMvk++++Da5H'], - dataset: ['endpoint.events.library'], - }, - process: { - name: ['sshd.exe'], - pid: [9644], - entity_id: [ - 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTk2NDQtMTMyNTcwMzQwNDEuNzgyMTczODAw', - ], - executable: ['C:\\Program Files\\OpenSSH-Win64\\sshd.exe'], - }, - agent: { - type: ['endpoint'], - }, - user: { - name: ['SYSTEM'], - domain: ['NT AUTHORITY'], - }, - message: ['Endpoint DLL load event'], - timestamp: '2021-02-05T21:27:23.921Z', - _id: 'IAUYdHcBGrBB52F2zo8Q', -}; - -export const mockEndpointRegistryModificationEvent: Ecs = { - host: { - os: { - full: ['Windows Server 2019 Datacenter 1809 (10.0.17763.1697)'], - name: ['Windows'], - version: ['1809 (10.0.17763.1697)'], - family: ['windows'], - kernel: ['1809 (10.0.17763.1697)'], - platform: ['windows'], - }, - mac: ['aa:bb:cc:dd:ee:ff'], - name: ['win2019-endpoint-1'], - architecture: ['x86_64'], - ip: ['10.1.2.3'], - id: ['d8ad572e-d224-4044-a57d-f5a84c0dfe5d'], - }, - event: { - category: ['registry'], - kind: ['event'], - created: ['2021-02-04T13:44:31.559Z'], - module: ['endpoint'], - action: ['modification'], - type: ['change'], - id: ['LzzWB9jjGmCwGMvk++++CbOn'], - dataset: ['endpoint.events.registry'], - }, - process: { - name: ['GoogleUpdate.exe'], - pid: [7408], - entity_id: [ - 'MWQxNWNmOWUtM2RjNy01Yjk3LWY1ODYtNzQzZjdjMjUxOGIyLTc0MDgtMTMyNTY5MTk4NDguODY4NTI0ODAw', - ], - executable: ['C:\\Program Files (x86)\\Google\\Update\\GoogleUpdate.exe'], - }, - registry: { - hive: ['HKLM'], - key: [ - 'SOFTWARE\\WOW6432Node\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}\\CurrentState', - ], - path: [ - 'HKLM\\SOFTWARE\\WOW6432Node\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}\\CurrentState\\StateValue', - ], - value: ['StateValue'], - }, - agent: { - type: ['endpoint'], - }, - user: { - name: ['SYSTEM'], - domain: ['NT AUTHORITY'], - }, - message: ['Endpoint registry event'], - timestamp: '2021-02-04T13:44:31.559Z', - _id: '4cxLbXcBGrBB52F2uOfF', -}; diff --git a/x-pack/plugins/security_solution/public/common/mock/netflow.ts b/x-pack/plugins/security_solution/public/common/mock/netflow.ts index bc7d1c8a0dbd30..055760a2182c77 100644 --- a/x-pack/plugins/security_solution/public/common/mock/netflow.ts +++ b/x-pack/plugins/security_solution/public/common/mock/netflow.ts @@ -5,75 +5,4 @@ * 2.0. */ -import { ONE_MILLISECOND_AS_NANOSECONDS } from '../../timelines/components/formatted_duration/helpers'; -import type { Ecs } from '../../../common/ecs'; - -/** Returns mock data for testing the Netflow component */ -export const getMockNetflowData = (): Ecs => ({ - destination: { - bytes: [40], - geo: { - city_name: ['New York'], - continent_name: ['North America'], - country_iso_code: ['US'], - country_name: ['United States'], - region_name: ['New York'], - }, - ip: ['10.1.2.3'], - packets: [1], - port: [80], - }, - event: { - action: ['network_flow'], - category: ['network_traffic'], - duration: [ONE_MILLISECOND_AS_NANOSECONDS], - end: ['2018-11-12T19:03:25.936Z'], - start: ['2018-11-12T19:03:25.836Z'], - }, - _id: 'abcd', - network: { - bytes: [100], - community_id: ['we.live.in.a'], - direction: ['outgoing'], - packets: [3], - protocol: ['http'], - transport: ['tcp'], - }, - process: { - name: ['rat'], - }, - source: { - bytes: [60], - geo: { - city_name: ['Atlanta'], - continent_name: ['North America'], - country_iso_code: ['US'], - country_name: ['United States'], - region_name: ['Georgia'], - }, - ip: ['192.168.1.2'], - packets: [2], - port: [9987], - }, - timestamp: '2018-11-12T19:03:25.936Z', - tls: { - client_certificate: { - fingerprint: { - sha1: ['tls.client_certificate.fingerprint.sha1-value'], - }, - }, - fingerprints: { - ja3: { - hash: ['tls.fingerprints.ja3.hash-value'], - }, - }, - server_certificate: { - fingerprint: { - sha1: ['tls.server_certificate.fingerprint.sha1-value'], - }, - }, - }, - user: { - name: ['first.last'], - }, -}); +export { getDemoNetflowData as getMockNetflowData } from '../demo_data/netflow'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx index c98f5616b17500..8da9e0e05d0750 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/index.tsx @@ -25,6 +25,3 @@ export const EndpointsContainer = memo(() => { }); EndpointsContainer.displayName = 'EndpointsContainer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -export { endpointListFleetApisHttpMock } from './mocks'; -export type { EndpointListFleetApisHttpMockInterface } from './mocks'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/alerts.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/alerts.tsx index 7183aa8e85d7e5..8acf2e42e845b9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/alerts.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/alerts.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndpointProcessExecutionMalwarePreventionAlert } from '../../../../common/mock/mock_timeline_data'; +import { demoEndpointProcessExecutionMalwarePreventionAlert } from '../../../../common/demo_data/endpoint/process_execution_malware_prevention_alert'; import { createEndpointAlertsRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; import { WAS_PREVENTED_FROM_EXECUTING_A_MALICIOUS_PROCESS } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -25,7 +24,7 @@ const AlertsExampleComponent: React.FC = () => { return ( <> {alertsRowRenderer.renderRow({ - data: mockEndpointProcessExecutionMalwarePreventionAlert, + data: demoEndpointProcessExecutionMalwarePreventionAlert, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd.tsx index d85f0537fe7204..40272e89bf789a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockTimelineData } from '../../../../common/mock/mock_timeline_data'; +import { demoTimelineData } from '../../../../common/demo_data/timeline'; import { createGenericAuditRowRenderer } from '../../timeline/body/renderers/auditd/generic_row_renderer'; import { CONNECTED_USING } from '../../timeline/body/renderers/auditd/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const AuditdExampleComponent: React.FC = () => { return ( <> {auditdRowRenderer.renderRow({ - data: mockTimelineData[26].ecs, + data: demoTimelineData[26].ecs, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd_file.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd_file.tsx index b55e667a6e43f3..b5a5cc70e0dc0e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd_file.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/auditd_file.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockTimelineData } from '../../../../common/mock/mock_timeline_data'; +import { demoTimelineData } from '../../../../common/demo_data/timeline'; import { createGenericFileRowRenderer } from '../../timeline/body/renderers/auditd/generic_row_renderer'; import { OPENED_FILE, USING } from '../../timeline/body/renderers/auditd/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const AuditdFileExampleComponent: React.FC = () => { return ( <> {auditdFileRowRenderer.renderRow({ - data: mockTimelineData[27].ecs, + data: demoTimelineData[27].ecs, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/library.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/library.tsx index c45555f9c31ace..db1727661d15d8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/library.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/library.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndpointLibraryLoadEvent } from '../../../../common/mock/mock_timeline_data'; +import { demoEndpointLibraryLoadEvent } from '../../../../common/demo_data/endpoint/library_load_event'; import { createEndpointLibraryRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; import { LOADED_LIBRARY } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const LibraryExampleComponent: React.FC = () => { return ( <> {libraryRowRenderer.renderRow({ - data: mockEndpointLibraryLoadEvent, + data: demoEndpointLibraryLoadEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/netflow.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/netflow.tsx index 06321441a34d7c..553bf4874dac0b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/netflow.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/netflow.tsx @@ -7,15 +7,14 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { getMockNetflowData } from '../../../../common/mock/netflow'; +import { getDemoNetflowData } from '../../../../common/demo_data/netflow'; import { netflowRowRenderer } from '../../timeline/body/renderers/netflow/netflow_row_renderer'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const NetflowExampleComponent: React.FC = () => ( <> {netflowRowRenderer.renderRow({ - data: getMockNetflowData(), + data: getDemoNetflowData(), isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/registry.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/registry.tsx index f4d39a6870e802..093abf2d1aa63a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/registry.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/registry.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndpointRegistryModificationEvent } from '../../../../common/mock/mock_timeline_data'; +import { demoEndpointRegistryModificationEvent } from '../../../../common/demo_data/endpoint/registry_modification_event'; import { createEndpointRegistryRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; import { MODIFIED_REGISTRY_KEY } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const RegistryExampleComponent: React.FC = () => { return ( <> {registryRowRenderer.renderRow({ - data: mockEndpointRegistryModificationEvent, + data: demoEndpointRegistryModificationEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/suricata.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/suricata.tsx index 613f6c632ad0c1..b385de92859e87 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/suricata.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/suricata.tsx @@ -7,15 +7,14 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockTimelineData } from '../../../../common/mock/mock_timeline_data'; +import { demoTimelineData } from '../../../../common/demo_data/timeline'; import { suricataRowRenderer } from '../../timeline/body/renderers/suricata/suricata_row_renderer'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const SuricataExampleComponent: React.FC = () => ( <> {suricataRowRenderer.renderRow({ - data: mockTimelineData[2].ecs, + data: demoTimelineData[2].ecs, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system.tsx index 2018f46865219e..bdf3e33af8426b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system.tsx @@ -9,8 +9,7 @@ import React from 'react'; import { TERMINATED_PROCESS } from '../../timeline/body/renderers/system/translations'; import { createGenericSystemRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameTerminationEvent } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameTerminationEvent } from '../../../../common/demo_data/endgame_ecs/termination'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const SystemExampleComponent: React.FC = () => { @@ -22,7 +21,7 @@ const SystemExampleComponent: React.FC = () => { return ( <> {systemRowRenderer.renderRow({ - data: mockEndgameTerminationEvent, + data: demoEndgameTerminationEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_dns.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_dns.tsx index aba609a8e53857..7f64a2faa66a79 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_dns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_dns.tsx @@ -8,8 +8,7 @@ import React from 'react'; import { createDnsRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameDnsRequest } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameDnsRequest } from '../../../../common/demo_data/endgame_ecs/dns'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const SystemDnsExampleComponent: React.FC = () => { @@ -18,7 +17,7 @@ const SystemDnsExampleComponent: React.FC = () => { return ( <> {systemDnsRowRenderer.renderRow({ - data: mockEndgameDnsRequest, + data: demoEndgameDnsRequest, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_endgame_process.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_endgame_process.tsx index c7c369c01ed1fc..d8c3ee2964a613 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_endgame_process.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_endgame_process.tsx @@ -8,8 +8,7 @@ import React from 'react'; import { createEndgameProcessRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameCreationEvent } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameCreationEvent } from '../../../../common/demo_data/endgame_ecs/creation'; import { PROCESS_STARTED } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const SystemEndgameProcessExampleComponent: React.FC = () => { return ( <> {systemEndgameProcessRowRenderer.renderRow({ - data: mockEndgameCreationEvent, + data: demoEndgameCreationEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_file.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_file.tsx index 72903035b2e129..0e24e7228ff3f4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_file.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_file.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameFileDeleteEvent } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameFileDeleteEvent } from '../../../../common/demo_data/endgame_ecs/file_events'; import { createGenericFileRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; import { DELETED_FILE } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const SystemFileExampleComponent: React.FC = () => { return ( <> {systemFileRowRenderer.renderRow({ - data: mockEndgameFileDeleteEvent, + data: demoEndgameFileDeleteEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_fim.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_fim.tsx index 74a02902fb78a2..9890b3b2f0c189 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_fim.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_fim.tsx @@ -7,8 +7,7 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameFileCreateEvent } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameFileCreateEvent } from '../../../../common/demo_data/endgame_ecs/file_events'; import { createFimRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; import { CREATED_FILE } from '../../timeline/body/renderers/system/translations'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; @@ -22,7 +21,7 @@ const SystemFimExampleComponent: React.FC = () => { return ( <> {systemFimRowRenderer.renderRow({ - data: mockEndgameFileCreateEvent, + data: demoEndgameFileCreateEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_security_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_security_event.tsx index aecf23ff08346c..d5380d34f3a0bf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_security_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_security_event.tsx @@ -8,8 +8,7 @@ import React from 'react'; import { createSecurityEventRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameUserLogon } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameUserLogon } from '../../../../common/demo_data/endgame_ecs/user_logon'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const SystemSecurityEventExampleComponent: React.FC = () => { @@ -20,7 +19,7 @@ const SystemSecurityEventExampleComponent: React.FC = () => { return ( <> {systemSecurityEventRowRenderer.renderRow({ - data: mockEndgameUserLogon, + data: demoEndgameUserLogon, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_socket.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_socket.tsx index 015a571ae6f5b3..5e57336e827ee5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_socket.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/system_socket.tsx @@ -9,8 +9,7 @@ import React from 'react'; import { ACCEPTED_A_CONNECTION_VIA } from '../../timeline/body/renderers/system/translations'; import { createSocketRowRenderer } from '../../timeline/body/renderers/system/generic_row_renderer'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockEndgameIpv4ConnectionAcceptEvent } from '../../../../common/mock/mock_endgame_ecs_data'; +import { demoEndgameIpv4ConnectionAcceptEvent } from '../../../../common/demo_data/endgame_ecs/ipv4'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const SystemSocketExampleComponent: React.FC = () => { @@ -21,7 +20,7 @@ const SystemSocketExampleComponent: React.FC = () => { return ( <> {systemSocketRowRenderer.renderRow({ - data: mockEndgameIpv4ConnectionAcceptEvent, + data: demoEndgameIpv4ConnectionAcceptEvent, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/threat_match.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/threat_match.tsx index ba3ca74147f296..3c96fd22fc6ed8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/threat_match.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/threat_match.tsx @@ -7,15 +7,14 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockTimelineData } from '../../../../common/mock/mock_timeline_data'; +import { demoTimelineData } from '../../../../common/demo_data/timeline'; import { threatMatchRowRenderer } from '../../timeline/body/renderers/cti/threat_match_row_renderer'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const ThreatMatchExampleComponent: React.FC = () => ( <> {threatMatchRowRenderer.renderRow({ - data: mockTimelineData[31].ecs, + data: demoTimelineData[31].ecs, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/zeek.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/zeek.tsx index ab8cab5e3d6977..714faad3b815d1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/zeek.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/examples/zeek.tsx @@ -7,15 +7,14 @@ import React from 'react'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -import { mockTimelineData } from '../../../../common/mock/mock_timeline_data'; +import { demoTimelineData } from '../../../../common/demo_data/timeline'; import { zeekRowRenderer } from '../../timeline/body/renderers/zeek/zeek_row_renderer'; import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../constants'; const ZeekExampleComponent: React.FC = () => ( <> {zeekRowRenderer.renderRow({ - data: mockTimelineData[13].ecs, + data: demoTimelineData[13].ecs, isDraggable: false, timelineId: ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID, })} diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 01759c01df53b0..8b9623b51b24ce 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -45,7 +45,7 @@ import { createEndpointMetadataServiceTestContextMock } from './services/metadat import type { EndpointAuthz } from '../../common/endpoint/types/authz'; import { EndpointFleetServicesFactory } from './services/fleet'; import { createLicenseServiceMock } from '../../common/license/mocks'; -import { createFeatureUsageServiceMock } from './services/feature_usage'; +import { createFeatureUsageServiceMock } from './services/feature_usage/mocks'; /** * Creates a mocked EndpointAppContext. diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 5746e1e93f9bb9..6eb04c9833e275 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -62,7 +62,7 @@ import { EndpointHostNotFoundError } from '../../services/metadata'; import { FleetAgentGenerator } from '../../../../common/endpoint/data_generators/fleet_agent_generator'; import { createMockAgentClient, createMockPackageService } from '@kbn/fleet-plugin/server/mocks'; import type { TransformGetTransformStatsResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz'; +import { getEndpointAuthzInitialStateMock } from '../../../../common/endpoint/service/authz/mocks'; class IndexNotFoundException extends Error { meta: { body: { error: { type: string } } }; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts index d65ea404f298d2..5c880f67847edc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/index.ts @@ -7,7 +7,5 @@ import { FeatureUsageService } from './service'; export type { FeatureKeys } from './service'; -// eslint-disable-next-line @kbn/imports/no_boundary_crossing -export { createFeatureUsageServiceMock, createMockPolicyData } from './mocks'; export const featureUsageService = new FeatureUsageService(); diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts index c93b8035aea8fd..0c6611acb77e09 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts @@ -43,7 +43,7 @@ import { Manifest } from '../endpoint/lib/artifacts'; import type { NewPackagePolicy } from '@kbn/fleet-plugin/common/types/models'; import type { ManifestSchema } from '../../common/endpoint/schema/manifest'; import type { DeletePackagePoliciesResponse } from '@kbn/fleet-plugin/common'; -import { createMockPolicyData } from '../endpoint/services/feature_usage'; +import { createMockPolicyData } from '../endpoint/services/feature_usage/mocks'; import { ALL_ENDPOINT_ARTIFACT_LIST_IDS } from '../../common/endpoint/service/artifacts/constants'; describe('ingest_integration tests ', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts index 0ac0a67a761ef2..282759546197f5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts @@ -32,7 +32,7 @@ import type { SecuritySolutionRequestHandlerContext, } from '../../../../types'; -import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz'; +import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks'; import type { EndpointAuthz } from '../../../../../common/endpoint/types/authz'; export const createMockClients = () => { From 6c438b331c703c507af524a13aab634cdbfbbb13 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 10 Aug 2022 17:17:50 -0500 Subject: [PATCH 02/59] [api-docs] follow the correct schema for frontmatter (#138348) * [api-docs] follow the correct schema for frontmatter * rename non-generated summary: usage * fix yaml comment syntax --- STYLEGUIDE.mdx | 2 +- dev_docs/contributing/best_practices.mdx | 2 +- dev_docs/contributing/code_walkthrough.mdx | 2 +- dev_docs/contributing/dev_principles.mdx | 2 +- dev_docs/contributing/documentation.mdx | 2 +- dev_docs/contributing/how_we_use_github.mdx | 2 +- dev_docs/contributing/standards.mdx | 2 +- dev_docs/getting_started/dev_welcome.mdx | 2 +- dev_docs/getting_started/hello_world_plugin.mdx | 2 +- .../setting_up_a_development_env.mdx | 2 +- dev_docs/getting_started/troubleshooting.mdx | 2 +- dev_docs/key_concepts/anatomy_of_a_plugin.mdx | 2 +- dev_docs/key_concepts/audit_logging.mdx | 2 +- dev_docs/key_concepts/building_blocks.mdx | 2 +- dev_docs/key_concepts/data_views.mdx | 2 +- dev_docs/key_concepts/embeddables.mdx | 2 +- .../key_concepts/kibana_platform_plugin_intro.mdx | 2 +- dev_docs/key_concepts/navigation.mdx | 2 +- dev_docs/key_concepts/performance.mdx | 2 +- dev_docs/key_concepts/persistable_state.mdx | 2 +- dev_docs/key_concepts/saved_objects.mdx | 2 +- dev_docs/tutorials/advanced_settings.mdx | 2 +- .../tutorials/building_a_kibana_distributable.mdx | 2 +- dev_docs/tutorials/ci.mdx | 2 +- dev_docs/tutorials/data/search.mdx | 2 +- dev_docs/tutorials/data_views.mdx | 2 +- dev_docs/tutorials/debugging.mdx | 2 +- dev_docs/tutorials/development_windows.mdx | 2 +- dev_docs/tutorials/endpoints.mdx | 2 +- dev_docs/tutorials/expressions.mdx | 2 +- dev_docs/tutorials/kibana_page_template.mdx | 2 +- dev_docs/tutorials/saved_objects.mdx | 2 +- dev_docs/tutorials/screenshotting.mdx | 2 +- dev_docs/tutorials/submit_a_pull_request.mdx | 2 +- dev_docs/tutorials/testing_plugins.mdx | 2 +- packages/home/sample_data_card/README.mdx | 2 +- packages/home/sample_data_tab/README.mdx | 2 +- .../src/api_docs/auto_generated_warning.ts | 12 ++++++++++++ .../api_docs/mdx/write_deprecations_doc_by_api.ts | 7 ++++--- .../mdx/write_deprecations_doc_by_plugin.ts | 9 +++++---- .../api_docs/mdx/write_deprecations_due_by_team.ts | 9 +++++---- .../src/api_docs/mdx/write_plugin_directory_doc.ts | 13 +++++++------ .../src/api_docs/mdx/write_plugin_mdx_docs.ts | 5 +++-- .../src/api_docs/tests/snapshots/plugin_a.mdx | 9 ++++++--- .../src/api_docs/tests/snapshots/plugin_a_foo.mdx | 9 ++++++--- .../src/api_docs/tests/snapshots/plugin_b.mdx | 9 ++++++--- packages/kbn-shared-ux-components/README.mdx | 2 +- .../src/page_template/page_template.mdx | 2 +- packages/kbn-shared-ux-services/README.mdx | 2 +- packages/kbn-shared-ux-storybook/README.mdx | 2 +- packages/kbn-shared-ux-utility/README.mdx | 2 +- packages/shared-ux/avatar/solution/README.mdx | 2 +- .../button/exit_full_screen/impl/README.mdx | 2 +- packages/shared-ux/button_toolbar/README.mdx | 2 +- .../button_toolbar/src/popover/popover.mdx | 2 +- packages/shared-ux/card/no_data/impl/README.mdx | 2 +- .../shared-ux/link/redirect_app/impl/README.mdx | 2 +- .../page/analytics_no_data/impl/README.mdx | 2 +- .../shared-ux/page/kibana_no_data/impl/README.mdx | 2 +- packages/shared-ux/page/solution_nav/README.mdx | 2 +- .../shared-ux/prompt/no_data_views/impl/README.mdx | 2 +- src/core/server/deprecations/README.mdx | 2 +- src/core/server/logging/README.mdx | 2 +- src/plugins/controls/README.mdx | 2 +- src/plugins/data/README.mdx | 2 +- src/plugins/data_views/README.mdx | 2 +- .../static/forms/docs/core/default_value.mdx | 2 +- .../static/forms/docs/core/field_hook.mdx | 2 +- .../static/forms/docs/core/form_component.mdx | 2 +- .../static/forms/docs/core/form_hook.mdx | 2 +- .../static/forms/docs/core/fundamentals.mdx | 2 +- .../static/forms/docs/core/use_array.mdx | 2 +- .../static/forms/docs/core/use_behavior_subject.mdx | 2 +- .../static/forms/docs/core/use_field.mdx | 2 +- .../static/forms/docs/core/use_form_data.mdx | 2 +- .../static/forms/docs/core/use_form_hook.mdx | 2 +- .../static/forms/docs/core/use_form_is_modified.mdx | 2 +- .../static/forms/docs/core/use_multi_fields.mdx | 2 +- .../static/forms/docs/examples/dynamic_fields.mdx | 2 +- .../forms/docs/examples/fields_composition.mdx | 2 +- .../forms/docs/examples/listening_to_changes.mdx | 2 +- .../docs/examples/serializers_deserializers.mdx | 2 +- .../static/forms/docs/examples/style_fields.mdx | 2 +- .../static/forms/docs/examples/validation.mdx | 2 +- .../static/forms/docs/helpers/components.mdx | 2 +- .../static/forms/docs/helpers/validators.mdx | 2 +- .../es_ui_shared/static/forms/docs/welcome.mdx | 2 +- src/plugins/presentation_util/README.mdx | 2 +- src/plugins/share/README.mdx | 2 +- src/plugins/shared_ux/docs/about.mdx | 2 +- src/plugins/usage_collection/README.mdx | 2 +- x-pack/plugins/canvas/PLUGINS.mdx | 2 +- x-pack/plugins/canvas/shareable_runtime/README.mdx | 2 +- 93 files changed, 138 insertions(+), 112 deletions(-) create mode 100644 packages/kbn-docs-utils/src/api_docs/auto_generated_warning.ts diff --git a/STYLEGUIDE.mdx b/STYLEGUIDE.mdx index b06cfa44a4973a..8e043cba92249c 100644 --- a/STYLEGUIDE.mdx +++ b/STYLEGUIDE.mdx @@ -2,7 +2,7 @@ id: kibStyleGuide slug: /kibana-dev-docs/contributing/styleguide title: Style Guide -summary: JavaScript/TypeScript styleguide. +description: JavaScript/TypeScript styleguide. date: 2021-05-06 tags: ['kibana', 'onboarding', 'dev', 'styleguide', 'typescript', 'javascript'] --- diff --git a/dev_docs/contributing/best_practices.mdx b/dev_docs/contributing/best_practices.mdx index 3e7fca5539d770..16c66417b89c10 100644 --- a/dev_docs/contributing/best_practices.mdx +++ b/dev_docs/contributing/best_practices.mdx @@ -2,7 +2,7 @@ id: kibBestPractices slug: /kibana-dev-docs/contributing/best-practices title: Best practices -summary: Best practices to follow when building a Kibana plugin. +description: Best practices to follow when building a Kibana plugin. date: 2021-03-17 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/contributing/code_walkthrough.mdx b/dev_docs/contributing/code_walkthrough.mdx index 74995c246503c9..bae394887c20ef 100644 --- a/dev_docs/contributing/code_walkthrough.mdx +++ b/dev_docs/contributing/code_walkthrough.mdx @@ -2,7 +2,7 @@ id: kibRepoStructure slug: /kibana-dev-docs/contributing/repo-structure title: Repository structure -summary: High level walk-through of our repository structure. +description: High level walk-through of our repository structure. date: 2021-10-07 tags: ['contributor', 'dev', 'github', 'getting started', 'onboarding', 'kibana'] --- diff --git a/dev_docs/contributing/dev_principles.mdx b/dev_docs/contributing/dev_principles.mdx index 0b8f68d2323678..cbea79e658684b 100644 --- a/dev_docs/contributing/dev_principles.mdx +++ b/dev_docs/contributing/dev_principles.mdx @@ -2,7 +2,7 @@ id: kibDevPrinciples slug: /kibana-dev-docs/contributing/dev-principles title: Developer principles -summary: Follow our development principles to help keep our code base stable, maintainable and scalable. +description: Follow our development principles to help keep our code base stable, maintainable and scalable. date: 2021-03-04 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/contributing/documentation.mdx b/dev_docs/contributing/documentation.mdx index caf2f439548bcf..50cc0c8761400f 100644 --- a/dev_docs/contributing/documentation.mdx +++ b/dev_docs/contributing/documentation.mdx @@ -2,7 +2,7 @@ id: kibDocumentation slug: /kibana-dev-docs/contributing/documentation title: Documentation -summary: Writing documentation during development +description: Writing documentation during development date: 2022-03-01 tags: ['kibana', 'onboarding', 'dev'] --- diff --git a/dev_docs/contributing/how_we_use_github.mdx b/dev_docs/contributing/how_we_use_github.mdx index 339eebc89197ba..d427ba7d44f2e6 100644 --- a/dev_docs/contributing/how_we_use_github.mdx +++ b/dev_docs/contributing/how_we_use_github.mdx @@ -2,7 +2,7 @@ id: kibGitHub slug: /kibana-dev-docs/contributing/github title: How we use Github -summary: Forking, branching, committing and using labels in the Kibana GitHub repo +description: Forking, branching, committing and using labels in the Kibana GitHub repo date: 2021-09-16 tags: ['contributor', 'dev', 'github', 'getting started', 'onboarding', 'kibana'] --- diff --git a/dev_docs/contributing/standards.mdx b/dev_docs/contributing/standards.mdx index cef9199aee9243..1bb54ada1509c2 100644 --- a/dev_docs/contributing/standards.mdx +++ b/dev_docs/contributing/standards.mdx @@ -2,7 +2,7 @@ id: kibStandards slug: /kibana-dev-docs/standards title: Standards and guidelines -summary: Standards and guidelines we expect every Kibana developer to abide by +description: Standards and guidelines we expect every Kibana developer to abide by date: 2021-09-28 tags: ['contributor', 'dev', 'github', 'getting started', 'onboarding', 'kibana'] --- diff --git a/dev_docs/getting_started/dev_welcome.mdx b/dev_docs/getting_started/dev_welcome.mdx index 4080e0850b9468..4f5115af6b7314 100644 --- a/dev_docs/getting_started/dev_welcome.mdx +++ b/dev_docs/getting_started/dev_welcome.mdx @@ -2,7 +2,7 @@ id: kibDevDocsWelcome slug: /kibana-dev-docs/getting-started/welcome title: Welcome -summary: Build custom solutions and applications on top of Kibana. +description: Build custom solutions and applications on top of Kibana. date: 2021-01-02 tags: ['kibana', 'dev', 'contributor'] --- diff --git a/dev_docs/getting_started/hello_world_plugin.mdx b/dev_docs/getting_started/hello_world_plugin.mdx index 8fa4ea4316129a..08fd7e4a721c23 100644 --- a/dev_docs/getting_started/hello_world_plugin.mdx +++ b/dev_docs/getting_started/hello_world_plugin.mdx @@ -2,7 +2,7 @@ id: kibHelloWorldApp slug: /kibana-dev-docs/getting-started/hello-world-app title: Hello World -summary: Build a very basic plugin that registers an application that says "Hello World!". +description: Build a very basic plugin that registers an application that says "Hello World!". date: 2021-08-03 tags: ['kibana', 'dev', 'contributor', 'tutorials'] --- diff --git a/dev_docs/getting_started/setting_up_a_development_env.mdx b/dev_docs/getting_started/setting_up_a_development_env.mdx index bbbb356d9ea084..8599adf0e53b32 100644 --- a/dev_docs/getting_started/setting_up_a_development_env.mdx +++ b/dev_docs/getting_started/setting_up_a_development_env.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialSetupDevEnv slug: /kibana-dev-docs/getting-started/setup-dev-env title: Set up a Development Environment -summary: Learn how to setup a development environment for contributing to the Kibana repository +description: Learn how to setup a development environment for contributing to the Kibana repository date: 2022-07-07 tags: ['kibana', 'onboarding', 'dev', 'architecture', 'setup'] --- diff --git a/dev_docs/getting_started/troubleshooting.mdx b/dev_docs/getting_started/troubleshooting.mdx index b224a3200eefb8..cb0e1bad1bef56 100644 --- a/dev_docs/getting_started/troubleshooting.mdx +++ b/dev_docs/getting_started/troubleshooting.mdx @@ -2,7 +2,7 @@ id: kibTroubleshooting slug: /kibana-dev-docs/getting-started/troubleshooting title: Troubleshooting -summary: A collection of tips for working around strange issues. +description: A collection of tips for working around strange issues. date: 2021-09-08 tags: ['kibana', 'onboarding', 'dev', 'troubleshooting'] --- diff --git a/dev_docs/key_concepts/anatomy_of_a_plugin.mdx b/dev_docs/key_concepts/anatomy_of_a_plugin.mdx index f99c41ff18d07a..a126477ea4c2f4 100644 --- a/dev_docs/key_concepts/anatomy_of_a_plugin.mdx +++ b/dev_docs/key_concepts/anatomy_of_a_plugin.mdx @@ -2,7 +2,7 @@ id: kibDevAnatomyOfAPlugin slug: /kibana-dev-docs/key-concepts/anatomy-of-a-plugin title: Anatomy of a plugin -summary: Anatomy of a Kibana plugin. +description: Anatomy of a Kibana plugin. date: 2021-08-03 tags: ['kibana', 'onboarding', 'dev'] --- diff --git a/dev_docs/key_concepts/audit_logging.mdx b/dev_docs/key_concepts/audit_logging.mdx index 6ec4de320d5822..5546e52bf5dd87 100644 --- a/dev_docs/key_concepts/audit_logging.mdx +++ b/dev_docs/key_concepts/audit_logging.mdx @@ -2,7 +2,7 @@ id: kibAuditLogging slug: /kibana-dev-docs/key-concepts/audit-logging title: Audit Logging -summary: Audit Logging +description: Audit Logging date: 2022-06-15 tags: ['kibana', 'onboarding', 'dev', 'logging', 'audit'] --- diff --git a/dev_docs/key_concepts/building_blocks.mdx b/dev_docs/key_concepts/building_blocks.mdx index aeb2d2be7d6c93..5a7b79b93debf2 100644 --- a/dev_docs/key_concepts/building_blocks.mdx +++ b/dev_docs/key_concepts/building_blocks.mdx @@ -2,7 +2,7 @@ id: kibBuildingBlocks slug: /kibana-dev-docs/key-concepts/building-blocks title: Building blocks -summary: Consider these building blocks when developing your plugin. +description: Consider these building blocks when developing your plugin. date: 2021-02-24 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/key_concepts/data_views.mdx b/dev_docs/key_concepts/data_views.mdx index 6a0c2a701fae2b..59853f8e0c67e2 100644 --- a/dev_docs/key_concepts/data_views.mdx +++ b/dev_docs/key_concepts/data_views.mdx @@ -2,7 +2,7 @@ id: kibDataViewsKeyConcepts slug: /kibana-dev-docs/key-concepts/data-view-intro title: Data Views -summary: Data views are the central method of defining queryable data sets in Kibana +description: Data views are the central method of defining queryable data sets in Kibana date: 2021-08-11 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/dev_docs/key_concepts/embeddables.mdx b/dev_docs/key_concepts/embeddables.mdx index 2d5e14b7d4669f..f1a2bea5b9b128 100644 --- a/dev_docs/key_concepts/embeddables.mdx +++ b/dev_docs/key_concepts/embeddables.mdx @@ -2,7 +2,7 @@ id: kibDevDocsEmbeddables slug: /kibana-dev-docs/key-concepts/embeddables title: Embeddables -summary: Embeddables provide a way to expose a reusable widget. +description: Embeddables provide a way to expose a reusable widget. date: 2022-07-27 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/dev_docs/key_concepts/kibana_platform_plugin_intro.mdx b/dev_docs/key_concepts/kibana_platform_plugin_intro.mdx index 417d6e4983d4f7..98de7d082bc558 100644 --- a/dev_docs/key_concepts/kibana_platform_plugin_intro.mdx +++ b/dev_docs/key_concepts/kibana_platform_plugin_intro.mdx @@ -2,7 +2,7 @@ id: kibPlatformIntro slug: /kibana-dev-docs/key-concepts/platform-intro title: Plugins, packages, and the platform -summary: An introduction to the Kibana platform and how to use it to build a plugin. +description: An introduction to the Kibana platform and how to use it to build a plugin. date: 2021-01-06 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/key_concepts/navigation.mdx b/dev_docs/key_concepts/navigation.mdx index 6f3a5e737f91fa..e383f21187d41f 100644 --- a/dev_docs/key_concepts/navigation.mdx +++ b/dev_docs/key_concepts/navigation.mdx @@ -2,7 +2,7 @@ id: kibDevKeyConceptsNavigation slug: /kibana-dev-docs/routing-and-navigation title: Routing, Navigation and URL -summary: Learn best practices about navigation inside Kibana +description: Learn best practices about navigation inside Kibana date: 2021-10-05 tags: ['kibana', 'dev', 'architecture', 'contributor'] --- diff --git a/dev_docs/key_concepts/performance.mdx b/dev_docs/key_concepts/performance.mdx index c57630f508dcd3..4d808ed402d322 100644 --- a/dev_docs/key_concepts/performance.mdx +++ b/dev_docs/key_concepts/performance.mdx @@ -2,7 +2,7 @@ id: kibDevPerformance slug: /kibana-dev-docs/key-concepts/performance title: Performance -summary: Performance tips for Kibana development. +description: Performance tips for Kibana development. date: 2021-12-03 tags: ['kibana', 'onboarding', 'dev', 'performance'] --- diff --git a/dev_docs/key_concepts/persistable_state.mdx b/dev_docs/key_concepts/persistable_state.mdx index 25d3f37a86be42..75dae5447ffa0f 100644 --- a/dev_docs/key_concepts/persistable_state.mdx +++ b/dev_docs/key_concepts/persistable_state.mdx @@ -2,7 +2,7 @@ id: kibDevDocsPersistableStateIntro slug: /kibana-dev-docs/key-concepts/persistable-state-intro title: Persistable State -summary: Persitable state is a key concept to understand when building a Kibana plugin. +description: Persitable state is a key concept to understand when building a Kibana plugin. date: 2021-02-02 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/dev_docs/key_concepts/saved_objects.mdx b/dev_docs/key_concepts/saved_objects.mdx index 159e6e90a40378..ee974267c0bb98 100644 --- a/dev_docs/key_concepts/saved_objects.mdx +++ b/dev_docs/key_concepts/saved_objects.mdx @@ -2,7 +2,7 @@ id: kibDevDocsSavedObjectsIntro slug: /kibana-dev-docs/key-concepts/saved-objects-intro title: Saved Objects -summary: Saved Objects are a key concept to understand when building a Kibana plugin. +description: Saved Objects are a key concept to understand when building a Kibana plugin. date: 2021-02-02 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/dev_docs/tutorials/advanced_settings.mdx b/dev_docs/tutorials/advanced_settings.mdx index b0c12ad5e5eddc..d14da92edc93ca 100644 --- a/dev_docs/tutorials/advanced_settings.mdx +++ b/dev_docs/tutorials/advanced_settings.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialAdvancedSettings slug: /kibana-dev-docs/tutorials/advanced-settings title: How to register a new advanced setting -summary: Learn how to add and use a new advanced setting +description: Learn how to add and use a new advanced setting date: 2022-02-07 tags: ['kibana','onboarding', 'dev', 'architecture', 'tutorials'] --- diff --git a/dev_docs/tutorials/building_a_kibana_distributable.mdx b/dev_docs/tutorials/building_a_kibana_distributable.mdx index e73481058ab35b..d95f6246434b9b 100644 --- a/dev_docs/tutorials/building_a_kibana_distributable.mdx +++ b/dev_docs/tutorials/building_a_kibana_distributable.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialBuildingDistributable slug: /kibana-dev-docs/tutorials/building-distributable title: Building a Kibana distributable -summary: Learn how to build a Kibana distributable +description: Learn how to build a Kibana distributable date: 2021-05-10 tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'build', 'distributable'] --- diff --git a/dev_docs/tutorials/ci.mdx b/dev_docs/tutorials/ci.mdx index 32e5a8503a22c1..6598ed9855dc0b 100644 --- a/dev_docs/tutorials/ci.mdx +++ b/dev_docs/tutorials/ci.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialCI slug: /kibana-dev-docs/tutorials/ci title: CI -summary: CI +description: CI date: 2022-02-03 tags: ['kibana', 'onboarding', 'dev', 'ci'] --- diff --git a/dev_docs/tutorials/data/search.mdx b/dev_docs/tutorials/data/search.mdx index d422eb811b60bf..4c64dc0b02164e 100644 --- a/dev_docs/tutorials/data/search.mdx +++ b/dev_docs/tutorials/data/search.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialDataSearchAndSessions slug: /kibana-dev-docs/tutorials/data/search-and-sessions title: Kibana data.search Services -summary: Kibana Search Services +description: Kibana Search Services date: 2021-02-10 tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'search', 'sessions', 'search-sessions'] --- diff --git a/dev_docs/tutorials/data_views.mdx b/dev_docs/tutorials/data_views.mdx index eda4b34ac2fd4a..51aac0e3216925 100644 --- a/dev_docs/tutorials/data_views.mdx +++ b/dev_docs/tutorials/data_views.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialDataViews slug: /kibana-dev-docs/tutorials/data-views title: Data views API -summary: Data views API +description: Data views API date: 2021-08-11 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/tutorials/debugging.mdx b/dev_docs/tutorials/debugging.mdx index d5d86a9025303e..fabd475f88d776 100644 --- a/dev_docs/tutorials/debugging.mdx +++ b/dev_docs/tutorials/debugging.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialDebugging slug: /kibana-dev-docs/tutorials/debugging title: Debugging in development -summary: Learn how to debug Kibana while running from source +description: Learn how to debug Kibana while running from source date: 2021-04-26 tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'debugging'] --- diff --git a/dev_docs/tutorials/development_windows.mdx b/dev_docs/tutorials/development_windows.mdx index 0a39714dfd8ecc..ea872072057a37 100644 --- a/dev_docs/tutorials/development_windows.mdx +++ b/dev_docs/tutorials/development_windows.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialSetupWindowsDevWSL slug: /kibana-dev-docs/tutorial/setup-windows-development-wsl title: WSL on Windows Development -summary: Learn how to setup a Windows development environment using WSL +description: Learn how to setup a Windows development environment using WSL date: 2022-07-07 tags: ['kibana', 'onboarding', 'setup', 'windows', 'development', 'wsl'] --- diff --git a/dev_docs/tutorials/endpoints.mdx b/dev_docs/tutorials/endpoints.mdx index ab7aeda0e5693b..851c3046fead69 100644 --- a/dev_docs/tutorials/endpoints.mdx +++ b/dev_docs/tutorials/endpoints.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialServerEndpoint slug: /kibana-dev-docs/tutorials/registering-endpoints title: Registering and accessing an endpoint -summary: Learn how to register a new endpoint and access it +description: Learn how to register a new endpoint and access it date: 2021-11-24 tags: ['kibana', 'dev', 'architecture', 'tutorials'] --- diff --git a/dev_docs/tutorials/expressions.mdx b/dev_docs/tutorials/expressions.mdx index d9abf3dd57eb84..36df396306cac6 100644 --- a/dev_docs/tutorials/expressions.mdx +++ b/dev_docs/tutorials/expressions.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialExpressions slug: /kibana-dev-docs/tutorials/expressions title: Kibana Expressions Service -summary: Kibana Expressions Service +description: Kibana Expressions Service date: 2021-06-01 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/tutorials/kibana_page_template.mdx b/dev_docs/tutorials/kibana_page_template.mdx index f7169ea33cea73..5c037f4f3d0622 100644 --- a/dev_docs/tutorials/kibana_page_template.mdx +++ b/dev_docs/tutorials/kibana_page_template.mdx @@ -2,7 +2,7 @@ id: kibDevDocsKPTTutorial slug: /kibana-dev-docs/tutorials/kibana-page-template title: Kibana Page Template -summary: Learn how to create pages in Kibana +description: Learn how to create pages in Kibana date: 2021-03-20 tags: ['kibana', 'dev', 'ui', 'tutorials'] --- diff --git a/dev_docs/tutorials/saved_objects.mdx b/dev_docs/tutorials/saved_objects.mdx index a9d8cd7c6ec1c4..f922077cb5e546 100644 --- a/dev_docs/tutorials/saved_objects.mdx +++ b/dev_docs/tutorials/saved_objects.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialSavedObject slug: /kibana-dev-docs/tutorials/saved-objects title: Register a new saved object type -summary: Learn how to register a new saved object type. +description: Learn how to register a new saved object type. date: 2021-02-05 tags: ['kibana','onboarding', 'dev', 'architecture', 'tutorials'] --- diff --git a/dev_docs/tutorials/screenshotting.mdx b/dev_docs/tutorials/screenshotting.mdx index 76f28599284913..5d506e2cb13b4e 100644 --- a/dev_docs/tutorials/screenshotting.mdx +++ b/dev_docs/tutorials/screenshotting.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialScreenshotting slug: /kibana-dev-docs/tutorials/screenshotting title: Kibana Screenshotting Service -summary: Kibana Screenshotting Service +description: Kibana Screenshotting Service date: 2022-04-12 tags: ['kibana', 'onboarding', 'dev', 'architecture'] --- diff --git a/dev_docs/tutorials/submit_a_pull_request.mdx b/dev_docs/tutorials/submit_a_pull_request.mdx index f7d530f6cec663..0402a533b24985 100644 --- a/dev_docs/tutorials/submit_a_pull_request.mdx +++ b/dev_docs/tutorials/submit_a_pull_request.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialSubmitPullRequest slug: /kibana-dev-docs/tutorials/submit-pull-request title: Submitting a Kibana pull request -summary: Learn how to submit a Kibana pull request +description: Learn how to submit a Kibana pull request date: 2021-06-24 tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'github', 'pr', 'pull request', 'ci'] --- diff --git a/dev_docs/tutorials/testing_plugins.mdx b/dev_docs/tutorials/testing_plugins.mdx index b43fa19927cc49..4fbfd1b2574437 100644 --- a/dev_docs/tutorials/testing_plugins.mdx +++ b/dev_docs/tutorials/testing_plugins.mdx @@ -2,7 +2,7 @@ id: kibDevTutorialTestingPlugins slug: /kibana-dev-docs/tutorials/testing-plugins title: Testing Kibana Plugins -summary: Learn how to test different aspects of Kibana plugins +description: Learn how to test different aspects of Kibana plugins date: 2021-07-05 tags: ['kibana', 'onboarding', 'dev', 'architecture', 'testing'] --- diff --git a/packages/home/sample_data_card/README.mdx b/packages/home/sample_data_card/README.mdx index 5e2fa83830573a..a4cf6faddfac21 100644 --- a/packages/home/sample_data_card/README.mdx +++ b/packages/home/sample_data_card/README.mdx @@ -2,7 +2,7 @@ id: home/SampleData/Cards slug: /home/sample-data/cards title: Sample Data Cards -summary: A component that displays Sample Data Sets as cards and grid of cards. +description: A component that displays Sample Data Sets as cards and grid of cards. tags: ['home', 'component', 'sample-data'] date: 2022-06-30 --- diff --git a/packages/home/sample_data_tab/README.mdx b/packages/home/sample_data_tab/README.mdx index 7ad4ad5dab3e0a..8e9b6a373129b7 100644 --- a/packages/home/sample_data_tab/README.mdx +++ b/packages/home/sample_data_tab/README.mdx @@ -2,7 +2,7 @@ id: home/SampleData/Tab slug: /home/sample-data/tab title: Sample Data Tab -summary: A component that displays the content of the Sample Data tab in the `home` plugin. +description: A component that displays the content of the Sample Data tab in the `home` plugin. tags: ['home', 'component', 'sample-data'] date: 2022-06-30 --- diff --git a/packages/kbn-docs-utils/src/api_docs/auto_generated_warning.ts b/packages/kbn-docs-utils/src/api_docs/auto_generated_warning.ts new file mode 100644 index 00000000000000..055648f7b56699 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/auto_generated_warning.ts @@ -0,0 +1,12 @@ +/* + * 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 const AUTO_GENERATED_WARNING = `#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +####`; diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_api.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_api.ts index 156e09b2fce1b0..06532dc8a027f8 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_api.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_api.ts @@ -17,6 +17,7 @@ import { ReferencedDeprecationsByPlugin, UnreferencedDeprecationsByPlugin, } from '../types'; +import { AUTO_GENERATED_WARNING } from '../auto_generated_warning'; import { getPluginApiDocId } from '../utils'; export function writeDeprecationDocByApi( @@ -76,18 +77,18 @@ export function writeDeprecationDocByApi( const mdx = dedent(` --- +${AUTO_GENERATED_WARNING} id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API -summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. +description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. date: ${moment().format('YYYY-MM-DD')} tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- ## Referenced deprecated APIs -${tableMdx} +${tableMdx} ## Unreferenced deprecated APIs diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_plugin.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_plugin.ts index e79c109311c0b4..d25a42d7de50e2 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_plugin.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_doc_by_plugin.ts @@ -12,6 +12,7 @@ import dedent from 'dedent'; import fs from 'fs'; import Path from 'path'; import { ApiDeclaration, ApiReference, ReferencedDeprecationsByPlugin } from '../types'; +import { AUTO_GENERATED_WARNING } from '../auto_generated_warning'; import { getPluginApiDocId } from '../utils'; export function writeDeprecationDocByPlugin( @@ -34,7 +35,7 @@ export function writeDeprecationDocByPlugin( return ` ## ${key} - + | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| ${Object.keys(groupedDeprecationReferences) @@ -70,16 +71,16 @@ export function writeDeprecationDocByPlugin( const mdx = dedent(` --- +${AUTO_GENERATED_WARNING} id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin -summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. +description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. date: ${moment().format('YYYY-MM-DD')} tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- -${tableMdx} +${tableMdx} `); diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_due_by_team.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_due_by_team.ts index 712dd9c8e637ff..2defdb49aeaa0b 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_due_by_team.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_deprecations_due_by_team.ts @@ -16,6 +16,7 @@ import { PluginOrPackage, ReferencedDeprecationsByPlugin, } from '../types'; +import { AUTO_GENERATED_WARNING } from '../auto_generated_warning'; import { getPluginApiDocId } from '../utils'; export function writeDeprecationDueByTeam( @@ -58,7 +59,7 @@ export function writeDeprecationDueByTeam( return ` ## ${key} - + | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| ${Object.keys(groupedDeprecationReferences) @@ -97,16 +98,16 @@ export function writeDeprecationDueByTeam( const mdx = dedent(` --- +${AUTO_GENERATED_WARNING} id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team -summary: Lists the teams that are referencing deprecated APIs with a remove by date. +description: Lists the teams that are referencing deprecated APIs with a remove by date. date: ${moment().format('YYYY-MM-DD')} tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- -${tableMdx} +${tableMdx} `); diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_directory_doc.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_directory_doc.ts index c98621356439cb..129e1212625e39 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_directory_doc.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_directory_doc.ts @@ -11,6 +11,7 @@ import Path from 'path'; import dedent from 'dedent'; import { ToolingLog } from '@kbn/tooling-log'; import { PluginApi, PluginMetaInfo } from '../types'; +import { AUTO_GENERATED_WARNING } from '../auto_generated_warning'; import { getPluginApiDocId } from '../utils'; function hasPublicApi(doc: PluginApi): boolean { @@ -74,24 +75,24 @@ export function writePluginDirectoryDoc( const mdx = dedent(` --- +${AUTO_GENERATED_WARNING} id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory -summary: Directory of public APIs available through plugins or packages. +description: Directory of public APIs available through plugins or packages. date: ${moment().format('YYYY-MM-DD')} tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- ### Overall stats -| Count | Plugins or Packages with a
public API | Number of teams | +| Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| | ${totalStats.pluginCnt} | ${totalStats.pluginCntWithPublicApi} | ${totalStats.teamCnt} | ### Public API health stats -| API Count | Any Count | Missing comments | Missing exports | +| API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| | ${totalStats.totalApiCnt} | ${totalStats.anyCnt} | ${totalStats.missingCommentCnt} | ${ totalStats.missingExportCnt @@ -99,13 +100,13 @@ warning: This document is auto-generated and is meant to be viewed inside our ex ## Plugin Directory -| Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | +| Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| ${getDirectoryTable(pluginApiMap, pluginStatsMap, true)} ## Package Directory -| Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | +| Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| ${getDirectoryTable(pluginApiMap, pluginStatsMap, false)} diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts index 562d2a89817647..da65c9f6b33572 100644 --- a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts @@ -19,6 +19,7 @@ import { getSlug, } from '../utils'; import { writePluginDocSplitByFolder } from './write_plugin_split_by_folder'; +import { AUTO_GENERATED_WARNING } from '../auto_generated_warning'; import { WritePluginDocsOpts } from './types'; /** @@ -75,14 +76,14 @@ export function writePluginDoc( let mdx = dedent(` --- +${AUTO_GENERATED_WARNING} id: ${getPluginApiDocId(doc.id)} slug: /kibana-dev-docs/api/${slug} title: "${doc.id}" image: https://source.unsplash.com/400x175/?github -summary: API docs for the ${doc.id} plugin +description: API docs for the ${doc.id} plugin date: ${moment().format('YYYY-MM-DD')} tags: ['contributor', 'dev', 'apidocs', 'kibana', '${doc.id}'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import ${json} from './${fileName}.devdocs.json'; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx index 6a66fa74f7c01c..b72bb38869f78c 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibPluginAPluginApi slug: /kibana-dev-docs/api/pluginA title: "pluginA" image: https://source.unsplash.com/400x175/?github -summary: API docs for the pluginA plugin -date: 2022-04-30 +description: API docs for the pluginA plugin +date: 2022-08-08 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import pluginAObj from './plugin_a.devdocs.json'; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx index 4082de63068955..f1b79e0d69ce51 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibPluginAFooPluginApi slug: /kibana-dev-docs/api/pluginA-foo title: "pluginA.foo" image: https://source.unsplash.com/400x175/?github -summary: API docs for the pluginA.foo plugin -date: 2022-04-30 +description: API docs for the pluginA.foo plugin +date: 2022-08-08 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA.foo'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import pluginAFooObj from './plugin_a_foo.devdocs.json'; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx index d69da971f7e3ee..2d0c28885f8d33 100644 --- a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_b.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibPluginBPluginApi slug: /kibana-dev-docs/api/pluginB title: "pluginB" image: https://source.unsplash.com/400x175/?github -summary: API docs for the pluginB plugin -date: 2022-04-30 +description: API docs for the pluginB plugin +date: 2022-08-08 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginB'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import pluginBObj from './plugin_b.devdocs.json'; diff --git a/packages/kbn-shared-ux-components/README.mdx b/packages/kbn-shared-ux-components/README.mdx index 8fee1571e52203..f4673a0804f317 100644 --- a/packages/kbn-shared-ux-components/README.mdx +++ b/packages/kbn-shared-ux-components/README.mdx @@ -2,7 +2,7 @@ id: kibSharedUXComponents slug: /kibana-dev-docs/shared-ux/packages/kbn-shared-ux-components title: Shared UX Components -summary: +description: date: 2022-03-11 tags: ['kibana', 'dev', 'sharedUX'] --- diff --git a/packages/kbn-shared-ux-components/src/page_template/page_template.mdx b/packages/kbn-shared-ux-components/src/page_template/page_template.mdx index 59acf8910cf298..fbaada158e2773 100644 --- a/packages/kbn-shared-ux-components/src/page_template/page_template.mdx +++ b/packages/kbn-shared-ux-components/src/page_template/page_template.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/PageTemplate slug: /shared-ux-components/page_template/page_template title: Page Template -summary: A Kibana-specific wrapper around `EuiTemplate` +description: A Kibana-specific wrapper around `EuiTemplate` tags: ['shared-ux', 'component'] date: 2022-04-04 --- diff --git a/packages/kbn-shared-ux-services/README.mdx b/packages/kbn-shared-ux-services/README.mdx index 2ef3040128c877..589aae4cc7ed2b 100755 --- a/packages/kbn-shared-ux-services/README.mdx +++ b/packages/kbn-shared-ux-services/README.mdx @@ -2,7 +2,7 @@ id: kibSharedUXServices slug: /kibana-dev-docs/shared-ux/packages/kbn-shared-ux-services title: Shared UX Services -summary: The `@kbn/shared-ux-services` package provides a thin service abstraction for components and solutions created by the Shared UX team. +description: The `@kbn/shared-ux-services` package provides a thin service abstraction for components and solutions created by the Shared UX team. date: 2022-03-11 tags: ['kibana', 'dev', 'sharedUX'] --- diff --git a/packages/kbn-shared-ux-storybook/README.mdx b/packages/kbn-shared-ux-storybook/README.mdx index cfebeedcd1ac35..11992e336e627c 100644 --- a/packages/kbn-shared-ux-storybook/README.mdx +++ b/packages/kbn-shared-ux-storybook/README.mdx @@ -2,7 +2,7 @@ id: kibSharedUXStorybook slug: /kibana-dev-docs/shared-ux/packages/kbn-shared-ux-storybook title: Shared UX Storybook -summary: The `@kbn/shared-ux-storybook` package provides Storybook assets for Shared UX and other teams. +description: The `@kbn/shared-ux-storybook` package provides Storybook assets for Shared UX and other teams. date: 2022-03-11 tags: ['kibana', 'dev', 'sharedUX'] --- diff --git a/packages/kbn-shared-ux-utility/README.mdx b/packages/kbn-shared-ux-utility/README.mdx index a3a3ee965f6993..ec91bc4b16ab80 100644 --- a/packages/kbn-shared-ux-utility/README.mdx +++ b/packages/kbn-shared-ux-utility/README.mdx @@ -2,7 +2,7 @@ id: kibSharedUXUtility slug: /kibana-dev-docs/shared-ux/packages/kbn-shared-ux-utility title: Shared UX Utilities -summary: The `@kbn/shared-ux-utility` package contains a set of React, DOM and other utilities. +description: The `@kbn/shared-ux-utility` package contains a set of React, DOM and other utilities. date: 2022-03-11 tags: ['kibana', 'dev', 'sharedUX'] --- diff --git a/packages/shared-ux/avatar/solution/README.mdx b/packages/shared-ux/avatar/solution/README.mdx index 841274441f6edb..86f5bed3cc8c21 100644 --- a/packages/shared-ux/avatar/solution/README.mdx +++ b/packages/shared-ux/avatar/solution/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/KibanaSolutionAvatar slug: /shared-ux/components/avatar-solution title: Solution Avatar -summary: A wrapper around `EuiAvatar` tailored for use in Kibana solutions. +description: A wrapper around `EuiAvatar` tailored for use in Kibana solutions. tags: ['shared-ux', 'component'] date: 2022-05-04 --- diff --git a/packages/shared-ux/button/exit_full_screen/impl/README.mdx b/packages/shared-ux/button/exit_full_screen/impl/README.mdx index 03a885ba6151cc..790cff6a72f23f 100644 --- a/packages/shared-ux/button/exit_full_screen/impl/README.mdx +++ b/packages/shared-ux/button/exit_full_screen/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/ExitFullScreenButton slug: /shared-ux/components/exit-full-screen-button title: Exit Full Screen Button -summary: A button that floats over the plugin workspace and allows someone to exit "full screen" mode. +description: A button that floats over the plugin workspace and allows someone to exit "full screen" mode. tags: ['shared-ux', 'component'] date: 2021-12-28 --- diff --git a/packages/shared-ux/button_toolbar/README.mdx b/packages/shared-ux/button_toolbar/README.mdx index fb693dab44498d..c073ef003cda41 100644 --- a/packages/shared-ux/button_toolbar/README.mdx +++ b/packages/shared-ux/button_toolbar/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/ButtonToolbar slug: /shared-ux/button-toolbar title: Button Toolbar -summary: +description: tags: ['shared-ux', 'component'] date: 2022-06-14 --- diff --git a/packages/shared-ux/button_toolbar/src/popover/popover.mdx b/packages/shared-ux/button_toolbar/src/popover/popover.mdx index d1ade51485ae40..dcdeb01de3f04f 100644 --- a/packages/shared-ux/button_toolbar/src/popover/popover.mdx +++ b/packages/shared-ux/button_toolbar/src/popover/popover.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/Popover slug: /shared-ux/components/toolbar/popovers/popover title: Toolbar Popover -summary: A popover component that can be placed within a toolbar button. +description: A popover component that can be placed within a toolbar button. tags: ['shared-ux', 'component'] date: 2022-03-28 --- diff --git a/packages/shared-ux/card/no_data/impl/README.mdx b/packages/shared-ux/card/no_data/impl/README.mdx index e2b044c27ac447..02b626fcc700b6 100644 --- a/packages/shared-ux/card/no_data/impl/README.mdx +++ b/packages/shared-ux/card/no_data/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/NoDataCard slug: /shared-ux/components/no-data-card title: No Data Card -summary: A card displayed when no data is available is available in Kibana. +description: A card displayed when no data is available is available in Kibana. tags: ['shared-ux', 'component'] date: 2022-06-15 --- diff --git a/packages/shared-ux/link/redirect_app/impl/README.mdx b/packages/shared-ux/link/redirect_app/impl/README.mdx index 07d4f75ab764d2..337ea5e0d8450d 100644 --- a/packages/shared-ux/link/redirect_app/impl/README.mdx +++ b/packages/shared-ux/link/redirect_app/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Components/AppLink slug: /shared-ux/components/redirect-app-links title: Redirect App Links -summary: A component for redirecting links contained within it to the appropriate Kibana solution without a page refresh. +description: A component for redirecting links contained within it to the appropriate Kibana solution without a page refresh. tags: ['shared-ux', 'component'] date: 2022-05-04 --- diff --git a/packages/shared-ux/page/analytics_no_data/impl/README.mdx b/packages/shared-ux/page/analytics_no_data/impl/README.mdx index 6ba0e9298c2645..0d5a5bae445efc 100644 --- a/packages/shared-ux/page/analytics_no_data/impl/README.mdx +++ b/packages/shared-ux/page/analytics_no_data/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Page/AnalyticsNoDataPage slug: /shared-ux/page/analytics-no-data-page title: Analytics "No Data" Page -summary: An entire page that can be displayed when Kibana "has no data", specifically for Analytics. +description: An entire page that can be displayed when Kibana "has no data", specifically for Analytics. tags: ['shared-ux', 'component'] date: 2021-12-28 --- diff --git a/packages/shared-ux/page/kibana_no_data/impl/README.mdx b/packages/shared-ux/page/kibana_no_data/impl/README.mdx index afa1bd95c19bd3..bc5dc37ac679a4 100644 --- a/packages/shared-ux/page/kibana_no_data/impl/README.mdx +++ b/packages/shared-ux/page/kibana_no_data/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Page/KibanaNoDataPage slug: /shared-ux/page/kibana-no-data title: Kibana No Data Page -summary: A page to be displayed when there is no data in Elasticsearch, or no data views. +description: A page to be displayed when there is no data in Elasticsearch, or no data views. tags: ['shared-ux', 'component'] date: 2022-04-20 --- diff --git a/packages/shared-ux/page/solution_nav/README.mdx b/packages/shared-ux/page/solution_nav/README.mdx index abad92c1e41081..6ddd8462237ba8 100644 --- a/packages/shared-ux/page/solution_nav/README.mdx +++ b/packages/shared-ux/page/solution_nav/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Page/SolutionNav slug: /shared-ux/page/solution-nav title: Solution Page Navigation -summary: A customized `EuiSideNav` for pages within Solutions in Kibana. +description: A customized `EuiSideNav` for pages within Solutions in Kibana. tags: ['shared-ux', 'component'] date: 2022-06-30 --- diff --git a/packages/shared-ux/prompt/no_data_views/impl/README.mdx b/packages/shared-ux/prompt/no_data_views/impl/README.mdx index a2bc63fed07653..26facfce8d86e2 100644 --- a/packages/shared-ux/prompt/no_data_views/impl/README.mdx +++ b/packages/shared-ux/prompt/no_data_views/impl/README.mdx @@ -2,7 +2,7 @@ id: sharedUX/Prompt/NoDataViews slug: /shared-ux/prompt/no-data-views title: No Data Views Prompt -summary: A prompt to be displayed when there is data in Elasticsearch, but no data views +description: A prompt to be displayed when there is data in Elasticsearch, but no data views tags: ['shared-ux', 'component', 'prompt', 'no-data'] date: 2022-02-09 --- diff --git a/src/core/server/deprecations/README.mdx b/src/core/server/deprecations/README.mdx index ed542610e753fb..2594bd2f0dd6b5 100644 --- a/src/core/server/deprecations/README.mdx +++ b/src/core/server/deprecations/README.mdx @@ -2,7 +2,7 @@ id: kibCoreDeprecationsService slug: /kibana-dev-docs/services/deprecations-service title: Core Deprecations service -summary: The Deprecations service helps surface deprecated configs and features for plugins to our users +description: The Deprecations service helps surface deprecated configs and features for plugins to our users date: 2021-06-27 tags: ['kibana','dev', 'contributor', 'api docs'] --- diff --git a/src/core/server/logging/README.mdx b/src/core/server/logging/README.mdx index 11437d1e8df20b..9b3cf8f77e24eb 100644 --- a/src/core/server/logging/README.mdx +++ b/src/core/server/logging/README.mdx @@ -3,7 +3,7 @@ id: kibCoreLogging slug: /kibana-dev-docs/services/logging title: Logging system image: https://source.unsplash.com/400x175/?Logging -summary: Core logging contains the system and service for Kibana logs. +description: Core logging contains the system and service for Kibana logs. date: 2020-12-02 tags: ['kibana','dev', 'contributor', 'api docs'] --- diff --git a/src/plugins/controls/README.mdx b/src/plugins/controls/README.mdx index 46ba1ed3ba9e70..d6805e814e7ff6 100644 --- a/src/plugins/controls/README.mdx +++ b/src/plugins/controls/README.mdx @@ -2,7 +2,7 @@ id: controls slug: /kibana-dev-docs/controls title: Controls Plugin -summary: Introduction to the Controls Plugin. +description: Introduction to the Controls Plugin. date: 2020-01-12 tags: ['kibana', 'controls', 'dashboard'] related: [] diff --git a/src/plugins/data/README.mdx b/src/plugins/data/README.mdx index a8cb06ff9e60b3..ca1bd6fd989545 100644 --- a/src/plugins/data/README.mdx +++ b/src/plugins/data/README.mdx @@ -3,7 +3,7 @@ id: kibDataPlugin slug: /kibana-dev-docs/key-concepts/data-plugin title: Data services image: https://source.unsplash.com/400x175/?Search -summary: The data plugin contains services for searching, querying and filtering. +description: The data plugin contains services for searching, querying and filtering. date: 2020-12-02 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/src/plugins/data_views/README.mdx b/src/plugins/data_views/README.mdx index 7fdd435db746ef..6d2ef4c97bb332 100644 --- a/src/plugins/data_views/README.mdx +++ b/src/plugins/data_views/README.mdx @@ -3,7 +3,7 @@ id: kibDataPlugin slug: /kibana-dev-docs/services/data-plugin title: Data services image: https://source.unsplash.com/400x175/?Search -summary: The data plugin contains services for searching, querying and filtering. +description: The data plugin contains services for searching, querying and filtering. date: 2020-12-02 tags: ['kibana', 'dev', 'contributor', 'api docs'] --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/default_value.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/default_value.mdx index 5e03d6ad165289..be5dc8034d0398 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/default_value.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/default_value.mdx @@ -2,7 +2,7 @@ id: formLibCoreDefaultValue slug: /form-lib/core/default-value title: Default value -summary: Initiate a field with the correct value +description: Initiate a field with the correct value tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/field_hook.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/field_hook.mdx index c7be88c4336a6c..8532a1857871c0 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/field_hook.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/field_hook.mdx @@ -2,7 +2,7 @@ id: formLibCoreFieldHook slug: /form-lib/core/field-hook title: Field hook -summary: You don't manually create them but you'll get all the love from them +description: You don't manually create them but you'll get all the love from them tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/form_component.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/form_component.mdx index df479b5c72f37e..db642ef846fca1 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/form_component.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/form_component.mdx @@ -2,7 +2,7 @@ id: formLibCoreFormComponent slug: /form-lib/core/form-component title:
-summary: The boundary of your form +description: The boundary of your form tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/form_hook.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/form_hook.mdx index 46fac236123fdd..824f9f6671384a 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/form_hook.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/form_hook.mdx @@ -2,7 +2,7 @@ id: formLibCoreFormHook slug: /form-lib/core/form-hook title: Form hook -summary: The heart of the lib; It manages your fields so you don't have to +description: The heart of the lib; It manages your fields so you don't have to tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/fundamentals.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/fundamentals.mdx index c168cb4115bc29..4276519c54e874 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/fundamentals.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/fundamentals.mdx @@ -2,7 +2,7 @@ id: formLibCoreFundamentals slug: /form-lib/core/fundamentals title: Fundamentals -summary: Let's understand the basics +description: Let's understand the basics tags: ['forms', 'kibana', 'dev'] date: 2022-03-18 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_array.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_array.mdx index b92880fdf806d2..ca849fd067ccb2 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_array.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_array.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseArray slug: /form-lib/core/use-array title: -summary: The perfect companion to generate dynamic fields +description: The perfect companion to generate dynamic fields tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_behavior_subject.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_behavior_subject.mdx index f7eca9c360ac4b..40190343f5bfea 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_behavior_subject.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_behavior_subject.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseBehaviorSubject slug: /form-lib/utils/use-behavior-subject title: useBehaviorSubject() -summary: Util to create a rxjs BehaviorSubject with a handler to change its value +description: Util to create a rxjs BehaviorSubject with a handler to change its value tags: ['forms', 'kibana', 'dev'] date: 2021-08-20 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx index dd073e0b38d1f3..d5729dc778816e 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_field.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseField slug: /form-lib/core/use-field title: -summary: Drop it anywhere in your and see the magic happen +description: Drop it anywhere in your and see the magic happen tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_data.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_data.mdx index 0deb449591871d..2e5f628a86370d 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_data.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_data.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseFormData slug: /form-lib/core/use-form-data title: useFormData() -summary: Get fields value updates from anywhere +description: Get fields value updates from anywhere tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_hook.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_hook.mdx index 21c77afd6dbceb..82cd0c88834a30 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_hook.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_hook.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseForm slug: /form-lib/core/use-form title: useForm() -summary: The only hook you'll need to declare a new form +description: The only hook you'll need to declare a new form tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_is_modified.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_is_modified.mdx index d90b9100a04afa..d7c0603cc07c5f 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_form_is_modified.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_form_is_modified.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseFormIsModified slug: /form-lib/core/use-form-is-modified title: useFormIsModified() -summary: Know when your form has been modified by the user +description: Know when your form has been modified by the user tags: ['forms', 'kibana', 'dev'] date: 2022-03-18 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/core/use_multi_fields.mdx b/src/plugins/es_ui_shared/static/forms/docs/core/use_multi_fields.mdx index 2a16b8e878be87..281db05d5f1a6c 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/core/use_multi_fields.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/core/use_multi_fields.mdx @@ -2,7 +2,7 @@ id: formLibCoreUseMultiFields slug: /form-lib/core/use-multi-fields title: -summary: Because sometimes you need more than one field +description: Because sometimes you need more than one field tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx index f2525d5a16fba7..82516423424f62 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx @@ -2,7 +2,7 @@ id: formLibExampleDynamicFields slug: /form-lib/examples/dynamic-fields title: Dynamic fields -summary: Let the user add any number of fields on the fly +description: Let the user add any number of fields on the fly tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx index 260908f94a790f..7e7cce5e81332a 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx @@ -2,7 +2,7 @@ id: formLibExampleFieldsComposition slug: /form-lib/examples/fields-composition title: Fields composition -summary: Be DRY and compose your form +description: Be DRY and compose your form tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/listening_to_changes.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/listening_to_changes.mdx index c99184f5a5c0e9..6574a7ca4e2d11 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/listening_to_changes.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/listening_to_changes.mdx @@ -2,7 +2,7 @@ id: formLibExampleListeningToChanges slug: /form-lib/examples/listening-to-changes title: Listening to changes -summary: React to changes deep down the tree +description: React to changes deep down the tree tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx index 393711b393e0f2..dd3b402e85e3fa 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx @@ -2,7 +2,7 @@ id: formLibExampleSerializersDeserializers slug: /form-lib/examples/serializers-deserializers title: Serializers & Deserializers -summary: No need for a 1:1 map of your API with your form fields, be creative! +description: No need for a 1:1 map of your API with your form fields, be creative! tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/style_fields.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/style_fields.mdx index db7c98772eddb9..81ed07ffd5dafb 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/style_fields.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/style_fields.mdx @@ -2,7 +2,7 @@ id: formLibExampleStyleFields slug: /form-lib/examples/styles-fields title: Style fields -summary: Customize your fields however you want +description: Customize your fields however you want tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx index 0f4e9617d9af32..c45cae8602f197 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/validation.mdx @@ -2,7 +2,7 @@ id: formLibExampleValidation slug: /form-lib/examples/validation title: Validation -summary: Don't let invalid data leak out of your form! +description: Don't let invalid data leak out of your form! tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx b/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx index 1b35e41a98739c..97ea955aaecb1d 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx @@ -2,7 +2,7 @@ id: formLibHelpersComponents slug: /form-lib/helpers/components title: Components -summary: Build complex forms the easy way +description: Build complex forms the easy way tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/helpers/validators.mdx b/src/plugins/es_ui_shared/static/forms/docs/helpers/validators.mdx index aba2d6dffb1ba3..7fbe4c4e38dc3e 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/helpers/validators.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/helpers/validators.mdx @@ -2,7 +2,7 @@ id: formLibHelpersValidators slug: /form-lib/helpers/validators title: Validators -summary: Build complex forms the easy way +description: Build complex forms the easy way tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/es_ui_shared/static/forms/docs/welcome.mdx b/src/plugins/es_ui_shared/static/forms/docs/welcome.mdx index 2d1156f403bff6..8a356868e49c26 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/welcome.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/welcome.mdx @@ -2,7 +2,7 @@ id: formLibWelcome slug: /form-lib/welcome title: Welcome -summary: Build complex forms the easy way +description: Build complex forms the easy way tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- diff --git a/src/plugins/presentation_util/README.mdx b/src/plugins/presentation_util/README.mdx index 2cbb03232b9dda..2fc73204db4e18 100755 --- a/src/plugins/presentation_util/README.mdx +++ b/src/plugins/presentation_util/README.mdx @@ -2,7 +2,7 @@ id: presentationUtilPlugin slug: /kibana-dev-docs/presentationPlugin title: Presentation Utility Plugin -summary: Introduction to the Presentation Utility Plugin. +description: Introduction to the Presentation Utility Plugin. date: 2020-01-12 tags: ['kibana', 'presentation', 'services'] related: [] diff --git a/src/plugins/share/README.mdx b/src/plugins/share/README.mdx index 1a1fef05878126..bb4433b54b4807 100644 --- a/src/plugins/share/README.mdx +++ b/src/plugins/share/README.mdx @@ -2,7 +2,7 @@ id: kibDevSharePluginReadme slug: /kibana-dev-docs/tutorials/share title: Kibana share Plugin -summary: Introduction to Kibana "share" plugin services (sharing popup menu, URL locators, and short URLs). +description: Introduction to Kibana "share" plugin services (sharing popup menu, URL locators, and short URLs). date: 2022-02-21 tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'share', 'url', 'short-url', 'locator'] --- diff --git a/src/plugins/shared_ux/docs/about.mdx b/src/plugins/shared_ux/docs/about.mdx index a31a9b99195f2c..213ce774be217e 100644 --- a/src/plugins/shared_ux/docs/about.mdx +++ b/src/plugins/shared_ux/docs/about.mdx @@ -2,7 +2,7 @@ id: sharedUX/About slug: /shared-ux/about title: About Shared UX -summary: . +description: . date: 2021-01-05 tags: ['shared-ux'] --- diff --git a/src/plugins/usage_collection/README.mdx b/src/plugins/usage_collection/README.mdx index 03d8f7badb8c2a..a703a3de00820b 100644 --- a/src/plugins/usage_collection/README.mdx +++ b/src/plugins/usage_collection/README.mdx @@ -2,7 +2,7 @@ id: kibUsageCollectionPlugin slug: /kibana-dev-docs/key-concepts/usage-collection-plugin title: Usage collection service -summary: The Usage Collection Service defines a set of APIs for other plugins to report the usage of their features. +description: The Usage Collection Service defines a set of APIs for other plugins to report the usage of their features. date: 2021-02-24 tags: ['kibana','dev', 'contributor', 'api docs'] --- diff --git a/x-pack/plugins/canvas/PLUGINS.mdx b/x-pack/plugins/canvas/PLUGINS.mdx index 77fe65f864607e..c0e0bc9c92f5ad 100644 --- a/x-pack/plugins/canvas/PLUGINS.mdx +++ b/x-pack/plugins/canvas/PLUGINS.mdx @@ -2,7 +2,7 @@ id: canvasPlugins slug: /playground/kibana/canvas-plugins title: Develop Canvas plugins -summary: Introduction to +description: Introduction to date: 2021-02-18 tags: ['kibana', 'canvas', 'plugins'] related: [] diff --git a/x-pack/plugins/canvas/shareable_runtime/README.mdx b/x-pack/plugins/canvas/shareable_runtime/README.mdx index a9d58bb3833d9c..07fbe7af278253 100644 --- a/x-pack/plugins/canvas/shareable_runtime/README.mdx +++ b/x-pack/plugins/canvas/shareable_runtime/README.mdx @@ -2,7 +2,7 @@ id: canvasShareableWorkpads slug: /playground/kibana/canvas-shareable-workpads title: Share a Canvas Workpad on a Website -summary: How to share a static snapshot of a workpad on an external website. +description: How to share a static snapshot of a workpad on an external website. date: 2021-02-18 tags: ['kibana', 'canvas', 'share'] related: [] From 138621090e24322e2a667d6ff6b3b747ffbdefb9 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Wed, 10 Aug 2022 17:29:42 -0500 Subject: [PATCH 03/59] [data views] Fix allowNoIndex on field refresh (#138328) * fix allow no index on field refresh --- .../common/data_views/data_views.test.ts | 30 ++++++++++++++++--- .../common/data_views/data_views.ts | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/plugins/data_views/common/data_views/data_views.test.ts b/src/plugins/data_views/common/data_views/data_views.test.ts index a823e54665709b..fcf60947db7586 100644 --- a/src/plugins/data_views/common/data_views/data_views.test.ts +++ b/src/plugins/data_views/common/data_views/data_views.test.ts @@ -21,7 +21,7 @@ import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; const createFieldsFetcher = () => ({ - getFieldsForWildcard: () => [], + getFieldsForWildcard: jest.fn(async () => []), } as any as IDataViewsApiClient); const fieldFormats = fieldFormatsMock; @@ -56,6 +56,7 @@ describe('IndexPatterns', () => { let indexPatternsNoAccess: DataViewsService; let savedObjectsClient: SavedObjectsClientCommon; let SOClientGetDelay = 0; + let apiClient: IDataViewsApiClient; const uiSettings = { get: () => Promise.resolve(false), getAll: () => {}, @@ -97,10 +98,12 @@ describe('IndexPatterns', () => { }; }); + apiClient = createFieldsFetcher(); + indexPatterns = new DataViewsService({ uiSettings, savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientCommon, - apiClient: createFieldsFetcher(), + apiClient, fieldFormats, onNotification: () => {}, onError: () => {}, @@ -112,7 +115,7 @@ describe('IndexPatterns', () => { indexPatternsNoAccess = new DataViewsService({ uiSettings, savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientCommon, - apiClient: createFieldsFetcher(), + apiClient, fieldFormats, onNotification: () => {}, onError: () => {}, @@ -441,6 +444,13 @@ describe('IndexPatterns', () => { expect(defaultDataViewResult?.id).toBe('id1'); expect(uiSettings.set).toBeCalledTimes(0); }); + }); + + describe('refreshFields', () => { + beforeEach(() => { + // preserve mocked functionality + jest.clearAllMocks(); + }); test('refreshFields includes runtimeFields', async () => { const indexPatternSpec: DataViewSpec = { @@ -455,10 +465,22 @@ describe('IndexPatterns', () => { title: 'test', }; + const indexPattern = await indexPatterns.create(indexPatternSpec); + await indexPatterns.refreshFields(indexPattern); + expect(indexPattern.fields.length).toBe(1); + }); + + test('refreshFields properly includes allowNoIndex', async () => { + const indexPatternSpec: DataViewSpec = { + allowNoIndex: true, + title: 'test', + }; + const indexPattern = await indexPatterns.create(indexPatternSpec); indexPatterns.refreshFields(indexPattern); - expect(indexPattern.fields.length).toBe(1); + // @ts-expect-error + expect(apiClient.getFieldsForWildcard.mock.calls[0][0].allowNoIndex).toBe(true); }); }); }); diff --git a/src/plugins/data_views/common/data_views/data_views.ts b/src/plugins/data_views/common/data_views/data_views.ts index c6782e82abc340..aca409ea086242 100644 --- a/src/plugins/data_views/common/data_views/data_views.ts +++ b/src/plugins/data_views/common/data_views/data_views.ts @@ -500,6 +500,7 @@ export class DataViewsService { this.getFieldsForWildcard({ type: indexPattern.type, rollupIndex: indexPattern?.typeMeta?.params?.rollup_index, + allowNoIndex: indexPattern.allowNoIndex, ...options, pattern: indexPattern.title as string, }); From e0b822fd461fc6466ee634f275f4425c4eabde88 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 10 Aug 2022 19:10:09 -0400 Subject: [PATCH 04/59] [api-docs] Daily api_docs build (#138577) --- api_docs/actions.mdx | 7 +- api_docs/advanced_settings.mdx | 7 +- api_docs/aiops.mdx | 7 +- api_docs/alerting.mdx | 7 +- api_docs/apm.mdx | 7 +- api_docs/banners.mdx | 7 +- api_docs/bfetch.mdx | 7 +- api_docs/canvas.mdx | 7 +- api_docs/cases.mdx | 7 +- api_docs/charts.mdx | 7 +- api_docs/cloud.mdx | 7 +- api_docs/cloud_security_posture.mdx | 7 +- api_docs/console.mdx | 7 +- api_docs/controls.mdx | 7 +- api_docs/core.mdx | 7 +- api_docs/core_application.mdx | 7 +- api_docs/core_chrome.mdx | 7 +- api_docs/core_saved_objects.mdx | 7 +- api_docs/custom_integrations.mdx | 7 +- api_docs/dashboard.devdocs.json | 76 ++++++ api_docs/dashboard.mdx | 9 +- api_docs/dashboard_enhanced.mdx | 7 +- api_docs/data.mdx | 7 +- api_docs/data_query.mdx | 7 +- api_docs/data_search.mdx | 7 +- api_docs/data_view_editor.mdx | 7 +- api_docs/data_view_field_editor.mdx | 7 +- api_docs/data_view_management.mdx | 7 +- api_docs/data_views.mdx | 7 +- api_docs/data_visualizer.mdx | 7 +- api_docs/deprecations_by_api.mdx | 9 +- api_docs/deprecations_by_plugin.mdx | 7 +- api_docs/deprecations_by_team.mdx | 7 +- api_docs/dev_tools.mdx | 7 +- api_docs/discover.mdx | 7 +- api_docs/discover_enhanced.mdx | 7 +- api_docs/elastic_apm_synthtrace.mdx | 7 +- api_docs/embeddable.devdocs.json | 92 ++++++++ api_docs/embeddable.mdx | 9 +- api_docs/embeddable_enhanced.mdx | 7 +- api_docs/encrypted_saved_objects.mdx | 7 +- api_docs/enterprise_search.mdx | 7 +- api_docs/es_ui_shared.mdx | 7 +- api_docs/event_annotation.mdx | 7 +- api_docs/event_log.mdx | 7 +- api_docs/expression_error.mdx | 7 +- api_docs/expression_gauge.mdx | 7 +- api_docs/expression_heatmap.mdx | 7 +- api_docs/expression_image.mdx | 7 +- api_docs/expression_legacy_metric_vis.mdx | 7 +- api_docs/expression_metric.mdx | 7 +- api_docs/expression_metric_vis.mdx | 7 +- api_docs/expression_partition_vis.mdx | 7 +- api_docs/expression_repeat_image.mdx | 7 +- api_docs/expression_reveal_image.mdx | 7 +- api_docs/expression_shape.mdx | 7 +- api_docs/expression_tagcloud.mdx | 7 +- api_docs/expression_x_y.mdx | 7 +- api_docs/expressions.mdx | 7 +- api_docs/features.mdx | 7 +- api_docs/field_formats.mdx | 7 +- api_docs/file_upload.mdx | 7 +- api_docs/fleet.mdx | 7 +- api_docs/global_search.mdx | 7 +- api_docs/home.mdx | 7 +- api_docs/index_lifecycle_management.mdx | 7 +- api_docs/index_management.mdx | 7 +- api_docs/infra.mdx | 7 +- api_docs/inspector.mdx | 7 +- api_docs/interactive_setup.mdx | 7 +- api_docs/kbn_ace.mdx | 7 +- api_docs/kbn_aiops_components.mdx | 7 +- api_docs/kbn_aiops_utils.mdx | 7 +- api_docs/kbn_alerts.mdx | 7 +- api_docs/kbn_analytics.mdx | 7 +- api_docs/kbn_analytics_client.mdx | 7 +- ..._analytics_shippers_elastic_v3_browser.mdx | 7 +- ...n_analytics_shippers_elastic_v3_common.mdx | 7 +- ...n_analytics_shippers_elastic_v3_server.mdx | 7 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 7 +- api_docs/kbn_apm_config_loader.mdx | 7 +- api_docs/kbn_apm_utils.mdx | 7 +- api_docs/kbn_axe_config.mdx | 7 +- api_docs/kbn_bazel_packages.mdx | 7 +- api_docs/kbn_ci_stats_core.mdx | 7 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 7 +- api_docs/kbn_ci_stats_reporter.mdx | 7 +- api_docs/kbn_cli_dev_mode.mdx | 7 +- api_docs/kbn_coloring.mdx | 7 +- api_docs/kbn_config.mdx | 7 +- api_docs/kbn_config_mocks.mdx | 7 +- api_docs/kbn_config_schema.mdx | 7 +- api_docs/kbn_core_analytics_browser.mdx | 7 +- .../kbn_core_analytics_browser_internal.mdx | 7 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 7 +- api_docs/kbn_core_analytics_server.mdx | 7 +- .../kbn_core_analytics_server_internal.mdx | 7 +- api_docs/kbn_core_analytics_server_mocks.mdx | 7 +- api_docs/kbn_core_base_browser_mocks.mdx | 7 +- api_docs/kbn_core_base_common.mdx | 7 +- api_docs/kbn_core_base_server_internal.mdx | 7 +- api_docs/kbn_core_base_server_mocks.mdx | 7 +- api_docs/kbn_core_capabilities_common.mdx | 7 +- api_docs/kbn_core_capabilities_server.mdx | 7 +- .../kbn_core_capabilities_server_mocks.mdx | 7 +- api_docs/kbn_core_config_server_internal.mdx | 7 +- api_docs/kbn_core_deprecations_browser.mdx | 7 +- ...kbn_core_deprecations_browser_internal.mdx | 7 +- .../kbn_core_deprecations_browser_mocks.mdx | 7 +- api_docs/kbn_core_deprecations_common.mdx | 7 +- api_docs/kbn_core_doc_links_browser.mdx | 7 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 7 +- api_docs/kbn_core_doc_links_server.mdx | 7 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 7 +- ...e_elasticsearch_client_server_internal.mdx | 7 +- ...core_elasticsearch_client_server_mocks.mdx | 7 +- api_docs/kbn_core_elasticsearch_server.mdx | 7 +- ...kbn_core_elasticsearch_server_internal.mdx | 7 +- .../kbn_core_elasticsearch_server_mocks.mdx | 7 +- .../kbn_core_environment_server_internal.mdx | 7 +- .../kbn_core_environment_server_mocks.mdx | 7 +- .../kbn_core_execution_context_browser.mdx | 7 +- ...ore_execution_context_browser_internal.mdx | 7 +- ...n_core_execution_context_browser_mocks.mdx | 7 +- .../kbn_core_execution_context_common.mdx | 7 +- .../kbn_core_execution_context_server.mdx | 7 +- ...core_execution_context_server_internal.mdx | 7 +- ...bn_core_execution_context_server_mocks.mdx | 7 +- api_docs/kbn_core_fatal_errors_browser.mdx | 7 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 7 +- api_docs/kbn_core_http_browser.mdx | 7 +- api_docs/kbn_core_http_browser_internal.mdx | 7 +- api_docs/kbn_core_http_browser_mocks.mdx | 7 +- api_docs/kbn_core_http_common.mdx | 7 +- .../kbn_core_http_context_server_mocks.mdx | 7 +- .../kbn_core_http_router_server_internal.mdx | 7 +- .../kbn_core_http_router_server_mocks.mdx | 7 +- api_docs/kbn_core_http_server.mdx | 7 +- api_docs/kbn_core_http_server_internal.mdx | 7 +- api_docs/kbn_core_http_server_mocks.mdx | 7 +- api_docs/kbn_core_i18n_browser.mdx | 7 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 7 +- .../kbn_core_injected_metadata_browser.mdx | 7 +- ...n_core_injected_metadata_browser_mocks.mdx | 7 +- ...kbn_core_integrations_browser_internal.mdx | 7 +- .../kbn_core_integrations_browser_mocks.mdx | 7 +- api_docs/kbn_core_logging_server.mdx | 7 +- api_docs/kbn_core_logging_server_internal.mdx | 7 +- api_docs/kbn_core_logging_server_mocks.mdx | 7 +- ...ore_metrics_collectors_server_internal.mdx | 7 +- ...n_core_metrics_collectors_server_mocks.mdx | 7 +- api_docs/kbn_core_metrics_server.mdx | 7 +- api_docs/kbn_core_metrics_server_internal.mdx | 7 +- api_docs/kbn_core_metrics_server_mocks.mdx | 7 +- api_docs/kbn_core_mount_utils_browser.mdx | 7 +- .../kbn_core_mount_utils_browser_internal.mdx | 7 +- api_docs/kbn_core_node_server.mdx | 7 +- api_docs/kbn_core_node_server_internal.mdx | 7 +- api_docs/kbn_core_node_server_mocks.mdx | 7 +- api_docs/kbn_core_notifications_browser.mdx | 7 +- ...bn_core_notifications_browser_internal.mdx | 7 +- .../kbn_core_notifications_browser_mocks.mdx | 7 +- api_docs/kbn_core_overlays_browser.mdx | 7 +- .../kbn_core_overlays_browser_internal.mdx | 7 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 7 +- api_docs/kbn_core_preboot_server.mdx | 7 +- api_docs/kbn_core_preboot_server_mocks.mdx | 7 +- .../kbn_core_saved_objects_api_browser.mdx | 7 +- .../kbn_core_saved_objects_api_server.mdx | 7 +- api_docs/kbn_core_saved_objects_browser.mdx | 7 +- ...bn_core_saved_objects_browser_internal.mdx | 7 +- .../kbn_core_saved_objects_browser_mocks.mdx | 7 +- api_docs/kbn_core_saved_objects_common.mdx | 7 +- api_docs/kbn_core_saved_objects_server.mdx | 7 +- ...core_test_helpers_deprecations_getters.mdx | 7 +- ...n_core_test_helpers_http_setup_browser.mdx | 7 +- api_docs/kbn_core_theme_browser.mdx | 7 +- api_docs/kbn_core_theme_browser_internal.mdx | 7 +- api_docs/kbn_core_theme_browser_mocks.mdx | 7 +- api_docs/kbn_core_ui_settings_browser.mdx | 7 +- .../kbn_core_ui_settings_browser_internal.mdx | 7 +- .../kbn_core_ui_settings_browser_mocks.mdx | 7 +- api_docs/kbn_core_ui_settings_common.mdx | 7 +- api_docs/kbn_crypto.mdx | 7 +- api_docs/kbn_crypto_browser.mdx | 7 +- api_docs/kbn_datemath.mdx | 7 +- api_docs/kbn_dev_cli_errors.mdx | 7 +- api_docs/kbn_dev_cli_runner.mdx | 7 +- api_docs/kbn_dev_proc_runner.mdx | 7 +- api_docs/kbn_dev_utils.mdx | 7 +- api_docs/kbn_doc_links.mdx | 7 +- api_docs/kbn_docs_utils.mdx | 7 +- api_docs/kbn_ebt_tools.mdx | 7 +- api_docs/kbn_es_archiver.mdx | 7 +- api_docs/kbn_es_errors.mdx | 7 +- api_docs/kbn_es_query.mdx | 7 +- api_docs/kbn_eslint_plugin_imports.mdx | 7 +- api_docs/kbn_field_types.mdx | 7 +- api_docs/kbn_find_used_node_modules.mdx | 7 +- api_docs/kbn_generate.mdx | 7 +- api_docs/kbn_get_repo_files.mdx | 7 +- api_docs/kbn_handlebars.mdx | 7 +- api_docs/kbn_hapi_mocks.mdx | 7 +- api_docs/kbn_home_sample_data_card.mdx | 7 +- api_docs/kbn_home_sample_data_tab.mdx | 7 +- api_docs/kbn_i18n.mdx | 7 +- api_docs/kbn_import_resolver.mdx | 7 +- api_docs/kbn_interpreter.mdx | 7 +- api_docs/kbn_io_ts_utils.mdx | 7 +- api_docs/kbn_jest_serializers.mdx | 7 +- api_docs/kbn_kibana_manifest_parser.mdx | 7 +- api_docs/kbn_kibana_manifest_schema.mdx | 7 +- api_docs/kbn_logging.mdx | 7 +- api_docs/kbn_logging_mocks.mdx | 7 +- api_docs/kbn_managed_vscode_config.mdx | 7 +- api_docs/kbn_mapbox_gl.mdx | 7 +- api_docs/kbn_ml_agg_utils.mdx | 7 +- api_docs/kbn_ml_is_populated_object.mdx | 7 +- api_docs/kbn_ml_string_hash.mdx | 7 +- api_docs/kbn_monaco.mdx | 7 +- api_docs/kbn_optimizer.mdx | 7 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 7 +- ..._performance_testing_dataset_extractor.mdx | 7 +- api_docs/kbn_plugin_generator.mdx | 7 +- api_docs/kbn_plugin_helpers.mdx | 7 +- api_docs/kbn_react_field.mdx | 7 +- api_docs/kbn_repo_source_classifier.mdx | 7 +- api_docs/kbn_rule_data_utils.mdx | 7 +- .../kbn_securitysolution_autocomplete.mdx | 7 +- api_docs/kbn_securitysolution_es_utils.mdx | 7 +- api_docs/kbn_securitysolution_hook_utils.mdx | 7 +- ..._securitysolution_io_ts_alerting_types.mdx | 7 +- .../kbn_securitysolution_io_ts_list_types.mdx | 7 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 7 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 7 +- ...kbn_securitysolution_list_api.devdocs.json | 30 ++- api_docs/kbn_securitysolution_list_api.mdx | 9 +- .../kbn_securitysolution_list_constants.mdx | 7 +- api_docs/kbn_securitysolution_list_hooks.mdx | 7 +- api_docs/kbn_securitysolution_list_utils.mdx | 7 +- api_docs/kbn_securitysolution_rules.mdx | 7 +- api_docs/kbn_securitysolution_t_grid.mdx | 7 +- api_docs/kbn_securitysolution_utils.mdx | 7 +- api_docs/kbn_server_http_tools.mdx | 7 +- api_docs/kbn_server_route_repository.mdx | 7 +- api_docs/kbn_shared_svg.mdx | 7 +- ...hared_ux_button_exit_full_screen_mocks.mdx | 7 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 7 +- api_docs/kbn_shared_ux_card_no_data.mdx | 7 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 7 +- api_docs/kbn_shared_ux_components.mdx | 7 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 7 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 7 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 7 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 7 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 7 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 7 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 7 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 7 +- api_docs/kbn_shared_ux_services.mdx | 7 +- api_docs/kbn_shared_ux_storybook.mdx | 7 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 7 +- api_docs/kbn_shared_ux_utility.mdx | 7 +- api_docs/kbn_some_dev_log.mdx | 7 +- api_docs/kbn_sort_package_json.mdx | 7 +- api_docs/kbn_std.mdx | 7 +- api_docs/kbn_stdio_dev_helpers.mdx | 7 +- api_docs/kbn_storybook.mdx | 7 +- api_docs/kbn_telemetry_tools.mdx | 7 +- api_docs/kbn_test.mdx | 7 +- api_docs/kbn_test_jest_helpers.mdx | 7 +- api_docs/kbn_tooling_log.mdx | 7 +- api_docs/kbn_type_summarizer.mdx | 7 +- api_docs/kbn_type_summarizer_core.mdx | 7 +- api_docs/kbn_typed_react_router_config.mdx | 7 +- api_docs/kbn_ui_theme.mdx | 7 +- api_docs/kbn_user_profile_components.mdx | 7 +- api_docs/kbn_utility_types.mdx | 7 +- api_docs/kbn_utility_types_jest.mdx | 7 +- api_docs/kbn_utils.mdx | 7 +- api_docs/kbn_yarn_lock_validator.mdx | 7 +- api_docs/kibana_overview.mdx | 7 +- api_docs/kibana_react.mdx | 7 +- api_docs/kibana_utils.mdx | 7 +- api_docs/kubernetes_security.mdx | 7 +- api_docs/lens.devdocs.json | 50 ++++ api_docs/lens.mdx | 9 +- api_docs/license_api_guard.mdx | 7 +- api_docs/license_management.mdx | 7 +- api_docs/licensing.mdx | 7 +- api_docs/lists.mdx | 7 +- api_docs/management.mdx | 7 +- api_docs/maps.devdocs.json | 47 +++- api_docs/maps.mdx | 9 +- api_docs/maps_ems.mdx | 7 +- api_docs/ml.mdx | 7 +- api_docs/monitoring.mdx | 7 +- api_docs/monitoring_collection.mdx | 7 +- api_docs/navigation.mdx | 7 +- api_docs/newsfeed.mdx | 7 +- api_docs/observability.mdx | 7 +- api_docs/osquery.mdx | 7 +- api_docs/plugin_directory.mdx | 29 ++- api_docs/presentation_util.mdx | 7 +- api_docs/remote_clusters.mdx | 7 +- api_docs/reporting.mdx | 7 +- api_docs/rollup.mdx | 7 +- api_docs/rule_registry.mdx | 7 +- api_docs/runtime_fields.mdx | 7 +- api_docs/saved_objects.mdx | 7 +- api_docs/saved_objects_management.mdx | 7 +- api_docs/saved_objects_tagging.mdx | 7 +- api_docs/saved_objects_tagging_oss.mdx | 7 +- api_docs/screenshot_mode.mdx | 7 +- api_docs/screenshotting.mdx | 7 +- api_docs/security.mdx | 7 +- api_docs/security_solution.mdx | 7 +- api_docs/session_view.mdx | 7 +- api_docs/share.mdx | 7 +- api_docs/shared_u_x.mdx | 7 +- api_docs/snapshot_restore.mdx | 7 +- api_docs/spaces.mdx | 7 +- api_docs/stack_alerts.mdx | 7 +- api_docs/task_manager.mdx | 7 +- api_docs/telemetry.mdx | 7 +- api_docs/telemetry_collection_manager.mdx | 7 +- api_docs/telemetry_collection_xpack.mdx | 7 +- api_docs/telemetry_management_section.mdx | 7 +- api_docs/threat_intelligence.mdx | 7 +- api_docs/timelines.mdx | 7 +- api_docs/transform.mdx | 7 +- api_docs/triggers_actions_ui.mdx | 7 +- api_docs/ui_actions.mdx | 7 +- api_docs/ui_actions_enhanced.mdx | 7 +- api_docs/unified_search.devdocs.json | 222 +++++++++++++++++- api_docs/unified_search.mdx | 9 +- api_docs/unified_search_autocomplete.mdx | 9 +- api_docs/url_forwarding.mdx | 7 +- api_docs/usage_collection.mdx | 7 +- api_docs/ux.mdx | 7 +- api_docs/vis_default_editor.mdx | 7 +- api_docs/vis_type_gauge.mdx | 7 +- api_docs/vis_type_heatmap.mdx | 7 +- api_docs/vis_type_pie.mdx | 7 +- api_docs/vis_type_table.mdx | 7 +- api_docs/vis_type_timelion.mdx | 7 +- api_docs/vis_type_timeseries.mdx | 7 +- api_docs/vis_type_vega.mdx | 7 +- api_docs/vis_type_vislib.mdx | 7 +- api_docs/vis_type_xy.mdx | 7 +- api_docs/visualizations.devdocs.json | 10 +- api_docs/visualizations.mdx | 7 +- 352 files changed, 2264 insertions(+), 716 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index c1274e9de8d537..d9debf86126342 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibActionsPluginApi slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github -summary: API docs for the actions plugin +description: API docs for the actions plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 6b898e269d87e9..d48c56ee4ba3b9 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibAdvancedSettingsPluginApi slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github -summary: API docs for the advancedSettings plugin +description: API docs for the advancedSettings plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 1612fec6b3e975..9b2bc406330fb2 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibAiopsPluginApi slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github -summary: API docs for the aiops plugin +description: API docs for the aiops plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index f0d87090462c69..0b79758b2bca5c 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibAlertingPluginApi slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github -summary: API docs for the alerting plugin +description: API docs for the alerting plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index a997550a52c4f9..c775ed9f7c780b 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibApmPluginApi slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github -summary: API docs for the apm plugin +description: API docs for the apm plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index c230845985c7b7..692c4c49903118 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibBannersPluginApi slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github -summary: API docs for the banners plugin +description: API docs for the banners plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 73e3f00fe1e78e..5fa356ed6b1a6c 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibBfetchPluginApi slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github -summary: API docs for the bfetch plugin +description: API docs for the bfetch plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 95ec1ae2cbe637..b99bcdf1047f9b 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCanvasPluginApi slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github -summary: API docs for the canvas plugin +description: API docs for the canvas plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 8aa1a1c9687c5f..9f89af0916e15c 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCasesPluginApi slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github -summary: API docs for the cases plugin +description: API docs for the cases plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index a019fbfd8f7cc1..3ca08a5cf52800 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibChartsPluginApi slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github -summary: API docs for the charts plugin +description: API docs for the charts plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index aef9a98b87d143..75d33bb6cb38d4 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCloudPluginApi slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github -summary: API docs for the cloud plugin +description: API docs for the cloud plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index cdff3aa52f2fac..73d38c0501fbeb 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCloudSecurityPosturePluginApi slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github -summary: API docs for the cloudSecurityPosture plugin +description: API docs for the cloudSecurityPosture plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 94d35af8f5f820..82eb9a8b5ffde3 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibConsolePluginApi slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github -summary: API docs for the console plugin +description: API docs for the console plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 09460acd1b1298..75b8f870d8d07a 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibControlsPluginApi slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github -summary: API docs for the controls plugin +description: API docs for the controls plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 2f8691e5706b4f..de7ed5719a1a06 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCorePluginApi slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github -summary: API docs for the core plugin +description: API docs for the core plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import coreObj from './core.devdocs.json'; diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index 351723d723c6b9..09667162a0bd57 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCoreApplicationPluginApi slug: /kibana-dev-docs/api/core-application title: "core.application" image: https://source.unsplash.com/400x175/?github -summary: API docs for the core.application plugin +description: API docs for the core.application plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.application'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import coreApplicationObj from './core_application.devdocs.json'; diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index abfb4f3cda3162..9cc2d6c8449d7b 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCoreChromePluginApi slug: /kibana-dev-docs/api/core-chrome title: "core.chrome" image: https://source.unsplash.com/400x175/?github -summary: API docs for the core.chrome plugin +description: API docs for the core.chrome plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.chrome'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import coreChromeObj from './core_chrome.devdocs.json'; diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index d84d7af14c1ee7..bab45e3b860fba 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCoreSavedObjectsPluginApi slug: /kibana-dev-docs/api/core-savedObjects title: "core.savedObjects" image: https://source.unsplash.com/400x175/?github -summary: API docs for the core.savedObjects plugin +description: API docs for the core.savedObjects plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.savedObjects'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import coreSavedObjectsObj from './core_saved_objects.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 86a28528ef9ef4..e6dcad20dee0cf 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibCustomIntegrationsPluginApi slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github -summary: API docs for the customIntegrations plugin +description: API docs for the customIntegrations plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.devdocs.json b/api_docs/dashboard.devdocs.json index cf48ab9df40cd3..01decee7cd29bb 100644 --- a/api_docs/dashboard.devdocs.json +++ b/api_docs/dashboard.devdocs.json @@ -81,6 +81,82 @@ "path": "src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx", "deprecated": false }, + { + "parentPluginId": "dashboard", + "id": "def-public.DashboardContainer.getAllDataViews", + "type": "Function", + "tags": [], + "label": "getAllDataViews", + "description": [ + "\nGets all the dataviews that are actively being used in the dashboard" + ], + "signature": [ + "() => ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]" + ], + "path": "src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx", + "deprecated": false, + "children": [], + "returnComment": [ + "An array of dataviews" + ] + }, + { + "parentPluginId": "dashboard", + "id": "def-public.DashboardContainer.setAllDataViews", + "type": "Function", + "tags": [], + "label": "setAllDataViews", + "description": [ + "\nUse this to set the dataviews that are used in the dashboard when they change/update" + ], + "signature": [ + "(newDataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]) => void" + ], + "path": "src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "dashboard", + "id": "def-public.DashboardContainer.setAllDataViews.$1", + "type": "Array", + "tags": [], + "label": "newDataViews", + "description": [ + "The new array of dataviews that will overwrite the old dataviews array" + ], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]" + ], + "path": "src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "dashboard", "id": "def-public.DashboardContainer.getPanelCount", diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 0850ff066d0821..7a35aae0ec2c9b 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDashboardPluginApi slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dashboard plugin +description: API docs for the dashboard plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dashboardObj from './dashboard.devdocs.json'; @@ -18,7 +21,7 @@ Contact [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-prese | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 143 | 0 | 141 | 12 | +| 146 | 0 | 141 | 12 | ## Client diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 9a4d938edfb2d2..a71ee95fbed8e0 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDashboardEnhancedPluginApi slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dashboardEnhanced plugin +description: API docs for the dashboardEnhanced plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index f9674f514c2066..75ba7f5d691a5b 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataPluginApi slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github -summary: API docs for the data plugin +description: API docs for the data plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 29460e1bd559d0..5e69ab274ba188 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataQueryPluginApi slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github -summary: API docs for the data.query plugin +description: API docs for the data.query plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index d2f2f7bc0829b7..9e6a0466aea6e0 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataSearchPluginApi slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github -summary: API docs for the data.search plugin +description: API docs for the data.search plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 2ad5853bb2f407..0f8f87d96257aa 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataViewEditorPluginApi slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dataViewEditor plugin +description: API docs for the dataViewEditor plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 5a4e3653b0aead..86cd795dd7dfe0 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataViewFieldEditorPluginApi slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dataViewFieldEditor plugin +description: API docs for the dataViewFieldEditor plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 942deac343a77d..5581c953daad00 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataViewManagementPluginApi slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dataViewManagement plugin +description: API docs for the dataViewManagement plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index d129adeffd6082..f94248c3e21918 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataViewsPluginApi slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dataViews plugin +description: API docs for the dataViews plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 926edb474e954d..a23db05ec0db5a 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDataVisualizerPluginApi slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github -summary: API docs for the dataVisualizer plugin +description: API docs for the dataVisualizer plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 153eae57516ff7..b2797246ab652e 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -1,11 +1,14 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API -summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. +description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- ## Referenced deprecated APIs @@ -96,7 +99,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ This is relied on by the reporting feature, and should be removed once reporting migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/issues/19914 | - + ## Unreferenced deprecated APIs diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index e58b5ba0a4aa20..1849ced937dcf7 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -1,11 +1,14 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin -summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. +description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 86c110b553d6bc..ed8f1ba63a87e9 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -1,11 +1,14 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team -summary: Lists the teams that are referencing deprecated APIs with a remove by date. +description: Lists the teams that are referencing deprecated APIs with a remove by date. date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 8d0eb77ba41c54..17efa22d534490 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDevToolsPluginApi slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github -summary: API docs for the devTools plugin +description: API docs for the devTools plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index b9ca0d5091db0e..f63dd0b8f2822d 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDiscoverPluginApi slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github -summary: API docs for the discover plugin +description: API docs for the discover plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index b50a8b5a34fccb..1c7810999e8878 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDiscoverEnhancedPluginApi slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github -summary: API docs for the discoverEnhanced plugin +description: API docs for the discoverEnhanced plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/elastic_apm_synthtrace.mdx b/api_docs/elastic_apm_synthtrace.mdx index 4c82dfcb262a89..de6c6e8d257503 100644 --- a/api_docs/elastic_apm_synthtrace.mdx +++ b/api_docs/elastic_apm_synthtrace.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibElasticApmSynthtracePluginApi slug: /kibana-dev-docs/api/elastic-apm-synthtrace title: "@elastic/apm-synthtrace" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @elastic/apm-synthtrace plugin +description: API docs for the @elastic/apm-synthtrace plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-synthtrace'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import elasticApmSynthtraceObj from './elastic_apm_synthtrace.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index ed0bc94fae658c..15b274a52b3c1d 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -4798,6 +4798,43 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "embeddable", + "id": "def-public.isFilterableEmbeddable", + "type": "Function", + "tags": [], + "label": "isFilterableEmbeddable", + "description": [ + "\nEnsure that embeddable supports filtering/querying" + ], + "signature": [ + "(incoming: unknown) => boolean" + ], + "path": "src/plugins/embeddable/public/lib/filterable_embeddable/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "embeddable", + "id": "def-public.isFilterableEmbeddable.$1", + "type": "Unknown", + "tags": [], + "label": "incoming", + "description": [ + "Embeddable that is being tested to check if it is a FilterableEmbeddable" + ], + "signature": [ + "unknown" + ], + "path": "src/plugins/embeddable/public/lib/filterable_embeddable/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [ + "true if the incoming embeddable is a FilterableEmbeddable, false if it is not" + ], + "initialIsOpen": false + }, { "parentPluginId": "embeddable", "id": "def-public.isRangeSelectTriggerContext", @@ -7430,6 +7467,61 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "embeddable", + "id": "def-public.FilterableEmbeddable", + "type": "Interface", + "tags": [], + "label": "FilterableEmbeddable", + "description": [ + "\nAll embeddables that implement this interface should support being filtered\nand/or queried via the top navigation bar" + ], + "path": "src/plugins/embeddable/public/lib/filterable_embeddable/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "embeddable", + "id": "def-public.FilterableEmbeddable.getFilters", + "type": "Function", + "tags": [], + "label": "getFilters", + "description": [ + "\nGets the embeddable's local filters" + ], + "signature": [ + "() => Promise<", + "Filter", + "[]>" + ], + "path": "src/plugins/embeddable/public/lib/filterable_embeddable/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "embeddable", + "id": "def-public.FilterableEmbeddable.getQuery", + "type": "Function", + "tags": [], + "label": "getQuery", + "description": [ + "\nGets the embeddable's local query" + ], + "signature": [ + "() => Promise<", + "Query", + " | ", + "AggregateQuery", + " | undefined>" + ], + "path": "src/plugins/embeddable/public/lib/filterable_embeddable/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "embeddable", "id": "def-public.IContainer", diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index ed91daaafbb5a4..f45e061cd95ab3 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEmbeddablePluginApi slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github -summary: API docs for the embeddable plugin +description: API docs for the embeddable plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import embeddableObj from './embeddable.devdocs.json'; @@ -18,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 507 | 0 | 413 | 4 | +| 512 | 0 | 413 | 4 | ## Client diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 91e5f95beee982..b0d4d7c2c24cbf 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEmbeddableEnhancedPluginApi slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github -summary: API docs for the embeddableEnhanced plugin +description: API docs for the embeddableEnhanced plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 1d7d67c0a6928f..a3914ef5316ce0 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEncryptedSavedObjectsPluginApi slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github -summary: API docs for the encryptedSavedObjects plugin +description: API docs for the encryptedSavedObjects plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index a544cb6aeda42d..62c7b7ab7751f9 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEnterpriseSearchPluginApi slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github -summary: API docs for the enterpriseSearch plugin +description: API docs for the enterpriseSearch plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 152bbc8e6a05c3..17c3fdf606766f 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEsUiSharedPluginApi slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github -summary: API docs for the esUiShared plugin +description: API docs for the esUiShared plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 4ae46dc78dddc0..d6d19f9a65f71a 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEventAnnotationPluginApi slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github -summary: API docs for the eventAnnotation plugin +description: API docs for the eventAnnotation plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 810257e6bd7542..daa352980179a2 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibEventLogPluginApi slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github -summary: API docs for the eventLog plugin +description: API docs for the eventLog plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 14425f584cf132..98a4a57dc96c8b 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionErrorPluginApi slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionError plugin +description: API docs for the expressionError plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 20a1cf38142fc4..44d2ca5d3a562c 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionGaugePluginApi slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionGauge plugin +description: API docs for the expressionGauge plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index 7b6c4543875255..e7f59d68e49542 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionHeatmapPluginApi slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionHeatmap plugin +description: API docs for the expressionHeatmap plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 6e44f7e1925bd1..60fb5ed4c81304 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionImagePluginApi slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionImage plugin +description: API docs for the expressionImage plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 66f01446ec8985..3192942b7153ae 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionLegacyMetricVisPluginApi slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionLegacyMetricVis plugin +description: API docs for the expressionLegacyMetricVis plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index c84e3ebe07e285..df59a5ac851b5b 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionMetricPluginApi slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionMetric plugin +description: API docs for the expressionMetric plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index fe81d139d71e69..418641075bcde2 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionMetricVisPluginApi slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionMetricVis plugin +description: API docs for the expressionMetricVis plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 1e14f753c20ef5..83ae6ccc351cb4 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionPartitionVisPluginApi slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionPartitionVis plugin +description: API docs for the expressionPartitionVis plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index c1a77887e01bcf..4d0209cb49ae48 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionRepeatImagePluginApi slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionRepeatImage plugin +description: API docs for the expressionRepeatImage plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index ffe31cd9065218..dd13abd47587a1 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionRevealImagePluginApi slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionRevealImage plugin +description: API docs for the expressionRevealImage plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 22ac6f5aa8f4c3..f691e0f454935c 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionShapePluginApi slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionShape plugin +description: API docs for the expressionShape plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index ae2e7c6c172b1d..ff37e4d33a3815 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionTagcloudPluginApi slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionTagcloud plugin +description: API docs for the expressionTagcloud plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index abef8921098c48..b36ba6f2ef3d5d 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionXYPluginApi slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressionXY plugin +description: API docs for the expressionXY plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 8265dab8d0b629..6107cfa5489977 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibExpressionsPluginApi slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github -summary: API docs for the expressions plugin +description: API docs for the expressions plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 4dbf73d2e9894c..acb0acbe2b4c44 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibFeaturesPluginApi slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github -summary: API docs for the features plugin +description: API docs for the features plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 1ed0f87b87f7c0..48ea69722201ae 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibFieldFormatsPluginApi slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github -summary: API docs for the fieldFormats plugin +description: API docs for the fieldFormats plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 23ef42b26d43d1..122761a52341f5 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibFileUploadPluginApi slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github -summary: API docs for the fileUpload plugin +description: API docs for the fileUpload plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 80b0f429435299..d566fb2abbed47 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibFleetPluginApi slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github -summary: API docs for the fleet plugin +description: API docs for the fleet plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index fc2c49c06221cb..75421786871619 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibGlobalSearchPluginApi slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github -summary: API docs for the globalSearch plugin +description: API docs for the globalSearch plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 89c35468ff05d5..19ac48f638e66c 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibHomePluginApi slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github -summary: API docs for the home plugin +description: API docs for the home plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index a0569cdca50815..b4c6de85363638 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibIndexLifecycleManagementPluginApi slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github -summary: API docs for the indexLifecycleManagement plugin +description: API docs for the indexLifecycleManagement plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index eb738f4c646d38..e671d6979edf36 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibIndexManagementPluginApi slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github -summary: API docs for the indexManagement plugin +description: API docs for the indexManagement plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 7723a94c956208..bd982b44e15db0 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibInfraPluginApi slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github -summary: API docs for the infra plugin +description: API docs for the infra plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 9d1b8650276bac..a6172213d301db 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibInspectorPluginApi slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github -summary: API docs for the inspector plugin +description: API docs for the inspector plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index d08e8b48732247..d4e8c0f6f9559d 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibInteractiveSetupPluginApi slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github -summary: API docs for the interactiveSetup plugin +description: API docs for the interactiveSetup plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 059821a6ee8b68..7bc465f202671d 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAcePluginApi slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ace plugin +description: API docs for the @kbn/ace plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 4c1649eb8c9534..e270cccdbb149e 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAiopsComponentsPluginApi slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/aiops-components plugin +description: API docs for the @kbn/aiops-components plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 97da08a9e054e4..e24d06855e463c 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAiopsUtilsPluginApi slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/aiops-utils plugin +description: API docs for the @kbn/aiops-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 712f797450c937..90a3d734258b5c 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAlertsPluginApi slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/alerts plugin +description: API docs for the @kbn/alerts plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 0871cfe033afe1..bd7fad52dade9d 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsPluginApi slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics plugin +description: API docs for the @kbn/analytics plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index b7cd57c8cb3503..ba5f94e88876c4 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsClientPluginApi slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics-client plugin +description: API docs for the @kbn/analytics-client plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 12c7c41b9010dc..15be83106b1efc 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsShippersElasticV3BrowserPluginApi slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin +description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 673437126d94f4..b4e0ad28d3c1e6 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsShippersElasticV3CommonPluginApi slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin +description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 52b8887fae27f8..c17ff240d5799e 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsShippersElasticV3ServerPluginApi slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin +description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index b00cba99dc65d6..1c1a422a1d3565 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAnalyticsShippersFullstoryPluginApi slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/analytics-shippers-fullstory plugin +description: API docs for the @kbn/analytics-shippers-fullstory plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index e4d53e0bacfd82..3a38ca144894ca 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnApmConfigLoaderPluginApi slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/apm-config-loader plugin +description: API docs for the @kbn/apm-config-loader plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index f0709c01d55224..f10d2d189fc2b8 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnApmUtilsPluginApi slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/apm-utils plugin +description: API docs for the @kbn/apm-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 34dec7bb8b7c2e..2c818293025947 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnAxeConfigPluginApi slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/axe-config plugin +description: API docs for the @kbn/axe-config plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bazel_packages.mdx b/api_docs/kbn_bazel_packages.mdx index 85685f06c59dd9..9b4470a79410ea 100644 --- a/api_docs/kbn_bazel_packages.mdx +++ b/api_docs/kbn_bazel_packages.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnBazelPackagesPluginApi slug: /kibana-dev-docs/api/kbn-bazel-packages title: "@kbn/bazel-packages" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/bazel-packages plugin +description: API docs for the @kbn/bazel-packages plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-packages'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnBazelPackagesObj from './kbn_bazel_packages.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 465efbdb066c14..55bc3cd497ae9c 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCiStatsCorePluginApi slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ci-stats-core plugin +description: API docs for the @kbn/ci-stats-core plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 10c1ee15848e97..97ab51ff028ad3 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCiStatsPerformanceMetricsPluginApi slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ci-stats-performance-metrics plugin +description: API docs for the @kbn/ci-stats-performance-metrics plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 1fe469a2f2b76e..59fbf29bda0bb2 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCiStatsReporterPluginApi slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ci-stats-reporter plugin +description: API docs for the @kbn/ci-stats-reporter plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index c41826cdf11a7d..25397ce8c1b2ba 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCliDevModePluginApi slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/cli-dev-mode plugin +description: API docs for the @kbn/cli-dev-mode plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index dbd9ea19feb480..623658e117bc75 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnColoringPluginApi slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/coloring plugin +description: API docs for the @kbn/coloring plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 49894b0045255f..30cbc67ed778a0 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnConfigPluginApi slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/config plugin +description: API docs for the @kbn/config plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index ea43e0d405a1cc..6ac320fb200733 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnConfigMocksPluginApi slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/config-mocks plugin +description: API docs for the @kbn/config-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 82ecdab7f42475..7fedf6ba97cc93 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnConfigSchemaPluginApi slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/config-schema plugin +description: API docs for the @kbn/config-schema plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index c09a2f9778701b..38c12fdfc2a3ae 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-browser plugin +description: API docs for the @kbn/core-analytics-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 11b8af9ab3439a..0cb2fad42af347 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-browser-internal plugin +description: API docs for the @kbn/core-analytics-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index c7fa438af75859..59ed1073c527d0 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-browser-mocks plugin +description: API docs for the @kbn/core-analytics-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index f00aad80106be0..557a5d3aa9b51b 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsServerPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-server plugin +description: API docs for the @kbn/core-analytics-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 5cda27736f13cb..9292a1959f45cd 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-server-internal plugin +description: API docs for the @kbn/core-analytics-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index ed0fd75a17ea1d..478dc44f58fb5a 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreAnalyticsServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-analytics-server-mocks plugin +description: API docs for the @kbn/core-analytics-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 4cf38273b434ec..2a213e335029f6 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreBaseBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-base-browser-mocks plugin +description: API docs for the @kbn/core-base-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index f998c3986fa42c..0cab7dd6adc34f 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreBaseCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-base-common plugin +description: API docs for the @kbn/core-base-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 7196db6502636d..1b790a3aa7fa63 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreBaseServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-base-server-internal plugin +description: API docs for the @kbn/core-base-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index e0fe87f10560ef..b5b479b107bff8 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreBaseServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-base-server-mocks plugin +description: API docs for the @kbn/core-base-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 4fe41d98f95e10..14dd1e84c9933a 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreCapabilitiesCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-capabilities-common plugin +description: API docs for the @kbn/core-capabilities-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 8dd31e759d3759..db5d0f23b0558f 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreCapabilitiesServerPluginApi slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-capabilities-server plugin +description: API docs for the @kbn/core-capabilities-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index ea93ab2a728a37..2d14bcb7fee9a6 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreCapabilitiesServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-capabilities-server-mocks plugin +description: API docs for the @kbn/core-capabilities-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 2022112d0f9689..89cf6d938e32f4 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreConfigServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-config-server-internal plugin +description: API docs for the @kbn/core-config-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 6b3592a5106a80..3b9fc2f3630f57 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDeprecationsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-deprecations-browser plugin +description: API docs for the @kbn/core-deprecations-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index c653204a2efa7a..d85d12d177bfcb 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDeprecationsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-deprecations-browser-internal plugin +description: API docs for the @kbn/core-deprecations-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index 5de45a3e441d2c..ebe495b965b47c 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDeprecationsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-deprecations-browser-mocks plugin +description: API docs for the @kbn/core-deprecations-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 9ec6d2b8e7de67..b1dcc85409acb6 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDeprecationsCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-deprecations-common plugin +description: API docs for the @kbn/core-deprecations-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 575fa27be8fc7c..2ee5b745daa87f 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDocLinksBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-doc-links-browser plugin +description: API docs for the @kbn/core-doc-links-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 979b7c9e29a0e5..d217f9f349cfbe 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDocLinksBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-doc-links-browser-mocks plugin +description: API docs for the @kbn/core-doc-links-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 1d8883729bc08d..7666fab1b2d457 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDocLinksServerPluginApi slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-doc-links-server plugin +description: API docs for the @kbn/core-doc-links-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 9d377f03024cfe..1e2b1c3cd2ef18 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreDocLinksServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-doc-links-server-mocks plugin +description: API docs for the @kbn/core-doc-links-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 71a70374fdcecf..a7a12a761133ef 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreElasticsearchClientServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-elasticsearch-client-server-internal plugin +description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index e30a930a510c23..c5b167a12681a5 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreElasticsearchClientServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin +description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 3e4d5ea1eff1e0..59400ce18d9a84 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreElasticsearchServerPluginApi slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-elasticsearch-server plugin +description: API docs for the @kbn/core-elasticsearch-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index d2c0ac6db57f5f..adf8c71f58e607 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreElasticsearchServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-elasticsearch-server-internal plugin +description: API docs for the @kbn/core-elasticsearch-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 4c7e3c5963d2dc..18bc9b36455909 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreElasticsearchServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-elasticsearch-server-mocks plugin +description: API docs for the @kbn/core-elasticsearch-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index 661d4f2ed8405c..e8a70ce60c7d5e 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreEnvironmentServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-environment-server-internal plugin +description: API docs for the @kbn/core-environment-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 4f5e63161fb700..a36ff455ffc242 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreEnvironmentServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-environment-server-mocks plugin +description: API docs for the @kbn/core-environment-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 64da2a18423480..11cbc9dac48fc3 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-browser plugin +description: API docs for the @kbn/core-execution-context-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 699750f0ccda92..0deb55eae32e75 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-browser-internal plugin +description: API docs for the @kbn/core-execution-context-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index f9da7f78d662ab..9f089a48f97ba4 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-browser-mocks plugin +description: API docs for the @kbn/core-execution-context-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 1164f75874838b..782d1fb88e738f 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-common plugin +description: API docs for the @kbn/core-execution-context-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 4709b3b984eb03..1d9901d9ff0c6c 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextServerPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-server plugin +description: API docs for the @kbn/core-execution-context-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 1041572776e692..18a8e96fe0bea4 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-server-internal plugin +description: API docs for the @kbn/core-execution-context-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index bf92cf80863884..e513446b139369 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreExecutionContextServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-execution-context-server-mocks plugin +description: API docs for the @kbn/core-execution-context-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 66fa9fd0d119e8..08e7d29db6a114 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreFatalErrorsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-fatal-errors-browser plugin +description: API docs for the @kbn/core-fatal-errors-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 93e50050c18277..41f541d1c27c9d 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreFatalErrorsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-fatal-errors-browser-mocks plugin +description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 7d478e7661cf21..539d5ea5677787 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-browser plugin +description: API docs for the @kbn/core-http-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 0196916c49af42..5b760bfab34ea3 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-browser-internal plugin +description: API docs for the @kbn/core-http-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 36e36ebcb79b99..bfedc44dd4d9ab 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-browser-mocks plugin +description: API docs for the @kbn/core-http-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 0ce137eaaf25ba..9bcce94ced59db 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-common plugin +description: API docs for the @kbn/core-http-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 7468336058974f..a9ec3d9417ed8c 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpContextServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-context-server-mocks plugin +description: API docs for the @kbn/core-http-context-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index a6333f53e2076b..f3c6a235da96bc 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpRouterServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-router-server-internal plugin +description: API docs for the @kbn/core-http-router-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 7566ee9119d107..ebadcfbaf2c389 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpRouterServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-router-server-mocks plugin +description: API docs for the @kbn/core-http-router-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 29e742f2350f8c..d916e2de8c61ae 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpServerPluginApi slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-server plugin +description: API docs for the @kbn/core-http-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 1254401ee5426a..09e6fbd78f3b16 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-server-internal plugin +description: API docs for the @kbn/core-http-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 8d66b2eda38ee0..ea492eafc4150e 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreHttpServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-http-server-mocks plugin +description: API docs for the @kbn/core-http-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index e7173c6deaab54..9c5ba3d8b049f9 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreI18nBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-i18n-browser plugin +description: API docs for the @kbn/core-i18n-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index ac518d3fba8849..c062fc2ef85d88 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreI18nBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-i18n-browser-mocks plugin +description: API docs for the @kbn/core-i18n-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 33b9777c89da10..2bc83f827cb968 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreInjectedMetadataBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-injected-metadata-browser plugin +description: API docs for the @kbn/core-injected-metadata-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 1b950e8fe94903..1ca36d6871b75b 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreInjectedMetadataBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-injected-metadata-browser-mocks plugin +description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 91b4acc9cadc8e..5d2be3bd28bf80 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreIntegrationsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-integrations-browser-internal plugin +description: API docs for the @kbn/core-integrations-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 3c46e98f755c9a..a5fd5222f6ff4d 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreIntegrationsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-integrations-browser-mocks plugin +description: API docs for the @kbn/core-integrations-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 8febbac2aba382..9c3429d1827fbb 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreLoggingServerPluginApi slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-logging-server plugin +description: API docs for the @kbn/core-logging-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 6a56cc215c2d2d..5c6fa6ce48ba53 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreLoggingServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-logging-server-internal plugin +description: API docs for the @kbn/core-logging-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index d694c5c983d204..71041214955905 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreLoggingServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-logging-server-mocks plugin +description: API docs for the @kbn/core-logging-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index c713d338cfd260..e7a96d9e147598 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMetricsCollectorsServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-metrics-collectors-server-internal plugin +description: API docs for the @kbn/core-metrics-collectors-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 7782767b072c51..7e3f3a73ae2bf3 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMetricsCollectorsServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-metrics-collectors-server-mocks plugin +description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index d3ba6875eb9938..d8421002909feb 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMetricsServerPluginApi slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-metrics-server plugin +description: API docs for the @kbn/core-metrics-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 1f4fa49cf81ed5..56679c0fac4f0c 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMetricsServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-metrics-server-internal plugin +description: API docs for the @kbn/core-metrics-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 44ef913936687f..4e2f78e552fc7f 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMetricsServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-metrics-server-mocks plugin +description: API docs for the @kbn/core-metrics-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index cd1db61a8b29d2..4001305370246a 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMountUtilsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-mount-utils-browser plugin +description: API docs for the @kbn/core-mount-utils-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser_internal.mdx b/api_docs/kbn_core_mount_utils_browser_internal.mdx index 2d690a60653575..554db464654d46 100644 --- a/api_docs/kbn_core_mount_utils_browser_internal.mdx +++ b/api_docs/kbn_core_mount_utils_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreMountUtilsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser-internal title: "@kbn/core-mount-utils-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-mount-utils-browser-internal plugin +description: API docs for the @kbn/core-mount-utils-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreMountUtilsBrowserInternalObj from './kbn_core_mount_utils_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 620d527e9dfec4..6fa8989f9a54a9 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNodeServerPluginApi slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-node-server plugin +description: API docs for the @kbn/core-node-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 5dc70b4e434d52..e1db2b6fc239bc 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNodeServerInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-node-server-internal plugin +description: API docs for the @kbn/core-node-server-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index a1c7f0518037ef..f054ee9e74e994 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNodeServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-node-server-mocks plugin +description: API docs for the @kbn/core-node-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 9b73ce6f2af07e..ed28d6e8607ccd 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNotificationsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-notifications-browser plugin +description: API docs for the @kbn/core-notifications-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index e26ac823e3a648..6c08452e5d9364 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNotificationsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-notifications-browser-internal plugin +description: API docs for the @kbn/core-notifications-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 8defd47de40676..bcf616f60134bb 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreNotificationsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-notifications-browser-mocks plugin +description: API docs for the @kbn/core-notifications-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 2ba9f8a19a0505..78fad3316f0d71 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreOverlaysBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-overlays-browser plugin +description: API docs for the @kbn/core-overlays-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 6f0a29e4680453..d941741e1979ef 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreOverlaysBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-overlays-browser-internal plugin +description: API docs for the @kbn/core-overlays-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 866132ba10c920..a16317e25c60b6 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreOverlaysBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-overlays-browser-mocks plugin +description: API docs for the @kbn/core-overlays-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index cbbf027250fe07..f87449e4a77ce4 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCorePrebootServerPluginApi slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-preboot-server plugin +description: API docs for the @kbn/core-preboot-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index a07a0853de6ae6..4ee9f89ec3c67e 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCorePrebootServerMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-preboot-server-mocks plugin +description: API docs for the @kbn/core-preboot-server-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 4083b402a8042d..7296fba5302cb0 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsApiBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-api-browser plugin +description: API docs for the @kbn/core-saved-objects-api-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 3db45c8be52f98..e2f0a1749d5aad 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsApiServerPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-api-server plugin +description: API docs for the @kbn/core-saved-objects-api-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 7a311807c83586..b18ef02e32332a 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-browser plugin +description: API docs for the @kbn/core-saved-objects-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 9967e10cdc76dc..47c87c5e56e1ec 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-browser-internal plugin +description: API docs for the @kbn/core-saved-objects-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 54dfcdbd7459aa..4ca709a50337cc 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-browser-mocks plugin +description: API docs for the @kbn/core-saved-objects-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index dc3a1986e550dd..c3cc2b35596314 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-common plugin +description: API docs for the @kbn/core-saved-objects-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 4f50d19daef663..f62f25d45463f6 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreSavedObjectsServerPluginApi slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-saved-objects-server plugin +description: API docs for the @kbn/core-saved-objects-server plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index fe65a7e89048c3..62df59fe050ff4 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreTestHelpersDeprecationsGettersPluginApi slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-test-helpers-deprecations-getters plugin +description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 99655563b1296d..ff0e91cf1de85b 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreTestHelpersHttpSetupBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-test-helpers-http-setup-browser plugin +description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index cf31e74dce003c..c289959f201805 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreThemeBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-theme-browser plugin +description: API docs for the @kbn/core-theme-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index eb88aa7a05bbd9..0494aba943d853 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreThemeBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-theme-browser-internal plugin +description: API docs for the @kbn/core-theme-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 92d27f90b7cf8a..f55a4a41bf4933 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreThemeBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-theme-browser-mocks plugin +description: API docs for the @kbn/core-theme-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 64f78476c8eeff..c1a5d83063ad2e 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreUiSettingsBrowserPluginApi slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-ui-settings-browser plugin +description: API docs for the @kbn/core-ui-settings-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 25c030f47a1e09..ed55bfb684e318 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreUiSettingsBrowserInternalPluginApi slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-ui-settings-browser-internal plugin +description: API docs for the @kbn/core-ui-settings-browser-internal plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 637c39c488705c..181658c6e1ced1 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreUiSettingsBrowserMocksPluginApi slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-ui-settings-browser-mocks plugin +description: API docs for the @kbn/core-ui-settings-browser-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index b93086e6d5a6e9..12cba7495172e3 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCoreUiSettingsCommonPluginApi slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/core-ui-settings-common plugin +description: API docs for the @kbn/core-ui-settings-common plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index f9dd8733c5c49b..fc4d3f1abd1c89 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCryptoPluginApi slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/crypto plugin +description: API docs for the @kbn/crypto plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index cb5d48578bd36e..b92c2d8d4e78ca 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnCryptoBrowserPluginApi slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/crypto-browser plugin +description: API docs for the @kbn/crypto-browser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index d91f60d78e1087..8d5531e2226e29 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDatemathPluginApi slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/datemath plugin +description: API docs for the @kbn/datemath plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 46bd0d8207f2ff..7e4b1ab51926df 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDevCliErrorsPluginApi slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/dev-cli-errors plugin +description: API docs for the @kbn/dev-cli-errors plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 7cb93cffe8c9d6..acd1f1bbf2b985 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDevCliRunnerPluginApi slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/dev-cli-runner plugin +description: API docs for the @kbn/dev-cli-runner plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 771e5cecdf43d4..41dbafc0bc1fb1 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDevProcRunnerPluginApi slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/dev-proc-runner plugin +description: API docs for the @kbn/dev-proc-runner plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 5342c7bfa04d91..0da804e752f452 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDevUtilsPluginApi slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/dev-utils plugin +description: API docs for the @kbn/dev-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index c371b30eb33384..0884a68cf4412a 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDocLinksPluginApi slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/doc-links plugin +description: API docs for the @kbn/doc-links plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 7665daea7144ce..891ded77cf277d 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnDocsUtilsPluginApi slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/docs-utils plugin +description: API docs for the @kbn/docs-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 63353d14673c91..fd93fb141ce85b 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnEbtToolsPluginApi slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ebt-tools plugin +description: API docs for the @kbn/ebt-tools plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index e48c751e54b5cb..0f807c0b43c12e 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnEsArchiverPluginApi slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/es-archiver plugin +description: API docs for the @kbn/es-archiver plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 46ac654c9d5e7e..393ecd76d6e92e 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnEsErrorsPluginApi slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/es-errors plugin +description: API docs for the @kbn/es-errors plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 5f6deb9a2917c2..1af39670b91094 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnEsQueryPluginApi slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/es-query plugin +description: API docs for the @kbn/es-query plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 4fb658ae8fe6ba..802105b6ab31fb 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnEslintPluginImportsPluginApi slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/eslint-plugin-imports plugin +description: API docs for the @kbn/eslint-plugin-imports plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 40554b64f05ace..d49b3b2f690ca7 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnFieldTypesPluginApi slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/field-types plugin +description: API docs for the @kbn/field-types plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index b857ce8b6e4f75..61c6b87747f72c 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnFindUsedNodeModulesPluginApi slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/find-used-node-modules plugin +description: API docs for the @kbn/find-used-node-modules plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 1cbaea812812dc..4c540cb90dcd2a 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnGeneratePluginApi slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/generate plugin +description: API docs for the @kbn/generate plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index 710252ce3a5c72..d1835b5faac093 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnGetRepoFilesPluginApi slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/get-repo-files plugin +description: API docs for the @kbn/get-repo-files plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 0c1c5162e78a64..9b4017593eee69 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnHandlebarsPluginApi slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/handlebars plugin +description: API docs for the @kbn/handlebars plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 8347122ac841db..9681a90d7fb4ec 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnHapiMocksPluginApi slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/hapi-mocks plugin +description: API docs for the @kbn/hapi-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 488d44e113ae8b..fdac17540890ce 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnHomeSampleDataCardPluginApi slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/home-sample-data-card plugin +description: API docs for the @kbn/home-sample-data-card plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 1eb25f2d0aabed..a261a5337cd520 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnHomeSampleDataTabPluginApi slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/home-sample-data-tab plugin +description: API docs for the @kbn/home-sample-data-tab plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index a142e7e1a75e4e..8aac8ce56d56e7 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnI18nPluginApi slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/i18n plugin +description: API docs for the @kbn/i18n plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index d89fbe0f1c21fb..af416592c96f43 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnImportResolverPluginApi slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/import-resolver plugin +description: API docs for the @kbn/import-resolver plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 5b2e1825b04461..c1efe00dc76ff1 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnInterpreterPluginApi slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/interpreter plugin +description: API docs for the @kbn/interpreter plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index a2504a4c32db6d..eec1b4e9073ba0 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnIoTsUtilsPluginApi slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/io-ts-utils plugin +description: API docs for the @kbn/io-ts-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 74a3f649a904a6..f7f8667e78e972 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnJestSerializersPluginApi slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/jest-serializers plugin +description: API docs for the @kbn/jest-serializers plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_parser.mdx b/api_docs/kbn_kibana_manifest_parser.mdx index cb8e3e9e4ab23f..03788cb327193a 100644 --- a/api_docs/kbn_kibana_manifest_parser.mdx +++ b/api_docs/kbn_kibana_manifest_parser.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnKibanaManifestParserPluginApi slug: /kibana-dev-docs/api/kbn-kibana-manifest-parser title: "@kbn/kibana-manifest-parser" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/kibana-manifest-parser plugin +description: API docs for the @kbn/kibana-manifest-parser plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-parser'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnKibanaManifestParserObj from './kbn_kibana_manifest_parser.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index ce71c1b8b75f04..03b946bd25a012 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnKibanaManifestSchemaPluginApi slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/kibana-manifest-schema plugin +description: API docs for the @kbn/kibana-manifest-schema plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 1151120643d1ae..724ed4fd38fe2f 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnLoggingPluginApi slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/logging plugin +description: API docs for the @kbn/logging plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index 3b7ee97c52ae1d..b72734dffbc206 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnLoggingMocksPluginApi slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/logging-mocks plugin +description: API docs for the @kbn/logging-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index ed6376e9553e12..b049ef5d8a506b 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnManagedVscodeConfigPluginApi slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/managed-vscode-config plugin +description: API docs for the @kbn/managed-vscode-config plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 8d6dba65ead910..dcd5593003f6af 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnMapboxGlPluginApi slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/mapbox-gl plugin +description: API docs for the @kbn/mapbox-gl plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 7cb8d90cfa235a..5f4db6fe80f91f 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnMlAggUtilsPluginApi slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ml-agg-utils plugin +description: API docs for the @kbn/ml-agg-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 6d72343154bdc4..02cc5334a886af 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnMlIsPopulatedObjectPluginApi slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ml-is-populated-object plugin +description: API docs for the @kbn/ml-is-populated-object plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index fe74228ef2800d..7d395d3a069a1b 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnMlStringHashPluginApi slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ml-string-hash plugin +description: API docs for the @kbn/ml-string-hash plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 5ad15805a570f1..3a8cfb0d9e5546 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnMonacoPluginApi slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/monaco plugin +description: API docs for the @kbn/monaco plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 5ceffe10c23555..401ffa5b6df92f 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnOptimizerPluginApi slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/optimizer plugin +description: API docs for the @kbn/optimizer plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index e87a7556a2f4d4..1433bed9a5223d 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnOptimizerWebpackHelpersPluginApi slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/optimizer-webpack-helpers plugin +description: API docs for the @kbn/optimizer-webpack-helpers plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index e783b89afa9358..d2547dbdf7c37a 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnPerformanceTestingDatasetExtractorPluginApi slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/performance-testing-dataset-extractor plugin +description: API docs for the @kbn/performance-testing-dataset-extractor plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 8528d35bdbf2d5..41377f5f936099 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnPluginGeneratorPluginApi slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/plugin-generator plugin +description: API docs for the @kbn/plugin-generator plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index d7c4a8b24e6191..4a00c6457c8b59 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnPluginHelpersPluginApi slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/plugin-helpers plugin +description: API docs for the @kbn/plugin-helpers plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index f6b280b0f03db9..7b4165dea7145d 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnReactFieldPluginApi slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/react-field plugin +description: API docs for the @kbn/react-field plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 40d5b8ffa349ec..1dc03a31b146fc 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnRepoSourceClassifierPluginApi slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/repo-source-classifier plugin +description: API docs for the @kbn/repo-source-classifier plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 443b445f4d402f..c99d36d31674a1 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnRuleDataUtilsPluginApi slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/rule-data-utils plugin +description: API docs for the @kbn/rule-data-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 7bed67d2eaf327..01381b9c64531f 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionAutocompletePluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-autocomplete plugin +description: API docs for the @kbn/securitysolution-autocomplete plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 5191717a2b4f65..b86f2b37fb312f 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionEsUtilsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-es-utils plugin +description: API docs for the @kbn/securitysolution-es-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 168432db590ca8..64447548f7b9db 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionHookUtilsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-hook-utils plugin +description: API docs for the @kbn/securitysolution-hook-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index dde361045dfca4..8021d578650f97 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionIoTsAlertingTypesPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin +description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 2e9052ebcb51ad..51c28cadb81b3a 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionIoTsListTypesPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-io-ts-list-types plugin +description: API docs for the @kbn/securitysolution-io-ts-list-types plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 912260c4b7f997..728f79e48e063f 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionIoTsTypesPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-io-ts-types plugin +description: API docs for the @kbn/securitysolution-io-ts-types plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 17c3de5b2ef010..f12bee7cba2f1f 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionIoTsUtilsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-io-ts-utils plugin +description: API docs for the @kbn/securitysolution-io-ts-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.devdocs.json b/api_docs/kbn_securitysolution_list_api.devdocs.json index f644bd3bfab69b..79b6b26e9f0980 100644 --- a/api_docs/kbn_securitysolution_list_api.devdocs.json +++ b/api_docs/kbn_securitysolution_list_api.devdocs.json @@ -496,7 +496,7 @@ "label": "findListsWithValidation", "description": [], "signature": [ - "({ cursor, http, pageIndex, pageSize, signal, }: ", + "({ cursor, http, pageIndex, pageSize, signal, sortField, sortOrder, }: ", { "pluginId": "@kbn/securitysolution-list-api", "scope": "common", @@ -514,7 +514,7 @@ "id": "def-common.findListsWithValidation.$1", "type": "Object", "tags": [], - "label": "{\n cursor,\n http,\n pageIndex,\n pageSize,\n signal,\n}", + "label": "{\n cursor,\n http,\n pageIndex,\n pageSize,\n signal,\n sortField,\n sortOrder,\n}", "description": [], "signature": [ { @@ -1011,6 +1011,32 @@ ], "path": "packages/kbn-securitysolution-list-api/src/list_api/types.ts", "deprecated": false + }, + { + "parentPluginId": "@kbn/securitysolution-list-api", + "id": "def-common.FindListsParams.sortOrder", + "type": "CompoundType", + "tags": [], + "label": "sortOrder", + "description": [], + "signature": [ + "\"asc\" | \"desc\" | undefined" + ], + "path": "packages/kbn-securitysolution-list-api/src/list_api/types.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/securitysolution-list-api", + "id": "def-common.FindListsParams.sortField", + "type": "string", + "tags": [], + "label": "sortField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-securitysolution-list-api/src/list_api/types.ts", + "deprecated": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 949bf45c71f1df..b350cdb74f58a8 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionListApiPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-list-api plugin +description: API docs for the @kbn/securitysolution-list-api plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; @@ -18,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 59 | 0 | 58 | 0 | +| 61 | 0 | 60 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index f0dbd8a1e3a591..c5982bc8047841 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionListConstantsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-list-constants plugin +description: API docs for the @kbn/securitysolution-list-constants plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 8d5a2429c99af8..47c226d31517a4 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionListHooksPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-list-hooks plugin +description: API docs for the @kbn/securitysolution-list-hooks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 2c061d5bbeec73..8e93c81a792c51 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionListUtilsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-list-utils plugin +description: API docs for the @kbn/securitysolution-list-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index a638dc939e2feb..7784aac276bbbb 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionRulesPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-rules plugin +description: API docs for the @kbn/securitysolution-rules plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 623e10d8a0e4a4..d19589e0fbf251 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionTGridPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-t-grid plugin +description: API docs for the @kbn/securitysolution-t-grid plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 3979cc17439544..05c368a4a14a24 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSecuritysolutionUtilsPluginApi slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/securitysolution-utils plugin +description: API docs for the @kbn/securitysolution-utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index c3668e264b8e41..604e4759040936 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnServerHttpToolsPluginApi slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/server-http-tools plugin +description: API docs for the @kbn/server-http-tools plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 72a014f25ba22b..40f966dda3f0ff 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnServerRouteRepositoryPluginApi slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/server-route-repository plugin +description: API docs for the @kbn/server-route-repository plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 0fde3962a5f48c..990fad803c7c25 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedSvgPluginApi slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-svg plugin +description: API docs for the @kbn/shared-svg plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index edecab3bd00f2c..60b5b3d3306260 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxButtonExitFullScreenMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin +description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index a4371e47e72f28..fccebd49555583 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxButtonToolbarPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-button-toolbar plugin +description: API docs for the @kbn/shared-ux-button-toolbar plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 8393837ce0d481..d293d0de06b6c5 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxCardNoDataPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-card-no-data plugin +description: API docs for the @kbn/shared-ux-card-no-data plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 84f7b5feb8e5f7..ab21403b9c618d 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxCardNoDataMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-card-no-data-mocks plugin +description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_components.mdx b/api_docs/kbn_shared_ux_components.mdx index 4dd9cb49f5f6f2..2cd1cfaf5b8ccb 100644 --- a/api_docs/kbn_shared_ux_components.mdx +++ b/api_docs/kbn_shared_ux_components.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxComponentsPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-components title: "@kbn/shared-ux-components" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-components plugin +description: API docs for the @kbn/shared-ux-components plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-components'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxComponentsObj from './kbn_shared_ux_components.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index c9247266d2047c..75fd35ae9d67c5 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxLinkRedirectAppMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin +description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index e2593344074303..1e6fc6e2ab71f6 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPageAnalyticsNoDataPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-page-analytics-no-data plugin +description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index d27d9840a5b1ff..016debf569b804 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPageAnalyticsNoDataMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin +description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 3644d7acad0930..1e0532f5aa87fd 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPageKibanaNoDataPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-page-kibana-no-data plugin +description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index d019b15d67759f..ef904ec8a5a709 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPageKibanaNoDataMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin +description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 29b118a38656b9..fa8e36b80886cf 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPageSolutionNavPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-page-solution-nav plugin +description: API docs for the @kbn/shared-ux-page-solution-nav plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index fda31d8d349108..77afd07c333deb 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPromptNoDataViewsPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-prompt-no-data-views plugin +description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 25bd1af3c2ed3b..6ddacd28b576a1 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxPromptNoDataViewsMocksPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin +description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_services.mdx b/api_docs/kbn_shared_ux_services.mdx index c22a7771b51989..385b93d1e9050d 100644 --- a/api_docs/kbn_shared_ux_services.mdx +++ b/api_docs/kbn_shared_ux_services.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxServicesPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-services title: "@kbn/shared-ux-services" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-services plugin +description: API docs for the @kbn/shared-ux-services plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-services'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxServicesObj from './kbn_shared_ux_services.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook.mdx b/api_docs/kbn_shared_ux_storybook.mdx index fc045d20ddf3ad..69abf887d35cec 100644 --- a/api_docs/kbn_shared_ux_storybook.mdx +++ b/api_docs/kbn_shared_ux_storybook.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxStorybookPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-storybook title: "@kbn/shared-ux-storybook" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-storybook plugin +description: API docs for the @kbn/shared-ux-storybook plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxStorybookObj from './kbn_shared_ux_storybook.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3595f0ef8c6b64..97535d2c0a7e1c 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxStorybookMockPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-storybook-mock plugin +description: API docs for the @kbn/shared-ux-storybook-mock plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 9b65d143ab6541..bae9f2e90952d9 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSharedUxUtilityPluginApi slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/shared-ux-utility plugin +description: API docs for the @kbn/shared-ux-utility plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 2051d3395ffa1e..23b03700d87da6 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSomeDevLogPluginApi slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/some-dev-log plugin +description: API docs for the @kbn/some-dev-log plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index c4befb85d9af4c..c1489a38ee153d 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnSortPackageJsonPluginApi slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/sort-package-json plugin +description: API docs for the @kbn/sort-package-json plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 2b6c2b5320fde6..19636d8cf53e98 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnStdPluginApi slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/std plugin +description: API docs for the @kbn/std plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 657bbdc0e9f4e4..bccf3025c5ba3b 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnStdioDevHelpersPluginApi slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/stdio-dev-helpers plugin +description: API docs for the @kbn/stdio-dev-helpers plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 30c0da2b24cb71..a3ff88389f2a9e 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnStorybookPluginApi slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/storybook plugin +description: API docs for the @kbn/storybook plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 95f4d0a0c39d62..c9532fe53827d6 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTelemetryToolsPluginApi slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/telemetry-tools plugin +description: API docs for the @kbn/telemetry-tools plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 54dc3daf11382a..027f4d88932b25 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTestPluginApi slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/test plugin +description: API docs for the @kbn/test plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 0555066353d71d..8a3442c98e962a 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTestJestHelpersPluginApi slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/test-jest-helpers plugin +description: API docs for the @kbn/test-jest-helpers plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 2c50d575b67c21..5127776b8be9ab 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnToolingLogPluginApi slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/tooling-log plugin +description: API docs for the @kbn/tooling-log plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index 5f9161ddc8121c..2664ecc3cff6c2 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTypeSummarizerPluginApi slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/type-summarizer plugin +description: API docs for the @kbn/type-summarizer plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index c2213c413022c9..7f7daf6d343d7d 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTypeSummarizerCorePluginApi slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/type-summarizer-core plugin +description: API docs for the @kbn/type-summarizer-core plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 7401bb90b53bee..2f6012dc105ea8 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnTypedReactRouterConfigPluginApi slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/typed-react-router-config plugin +description: API docs for the @kbn/typed-react-router-config plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 4ad76a0b2cce5b..e98d12e5e580ca 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnUiThemePluginApi slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/ui-theme plugin +description: API docs for the @kbn/ui-theme plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 315320ec121995..33d1d62a2807d6 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnUserProfileComponentsPluginApi slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/user-profile-components plugin +description: API docs for the @kbn/user-profile-components plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index b5f9fc136eb24f..b8c0a3eb58238a 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnUtilityTypesPluginApi slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/utility-types plugin +description: API docs for the @kbn/utility-types plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 820eaf6f617ee5..71fcef1e0eaa03 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnUtilityTypesJestPluginApi slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/utility-types-jest plugin +description: API docs for the @kbn/utility-types-jest plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 731bba55810056..2742f05a406626 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnUtilsPluginApi slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/utils plugin +description: API docs for the @kbn/utils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 02a3897d7c631c..0cc04b1399123a 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKbnYarnLockValidatorPluginApi slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github -summary: API docs for the @kbn/yarn-lock-validator plugin +description: API docs for the @kbn/yarn-lock-validator plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index a8020229ae9024..91d1b423874aa9 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKibanaOverviewPluginApi slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github -summary: API docs for the kibanaOverview plugin +description: API docs for the kibanaOverview plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index a6184ddccc5808..10c2cf52b0b3e7 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKibanaReactPluginApi slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github -summary: API docs for the kibanaReact plugin +description: API docs for the kibanaReact plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index dc2050c8311138..ef378071118f60 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKibanaUtilsPluginApi slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github -summary: API docs for the kibanaUtils plugin +description: API docs for the kibanaUtils plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 16b4fb5cb59193..9dd4e4953ae937 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibKubernetesSecurityPluginApi slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github -summary: API docs for the kubernetesSecurity plugin +description: API docs for the kubernetesSecurity plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 7f8e68796b1bcb..ec3a260fc858ec 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -54,6 +54,14 @@ "docId": "kibEmbeddablePluginApi", "section": "def-public.SelfStyledEmbeddable", "text": "SelfStyledEmbeddable" + }, + ",", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.FilterableEmbeddable", + "text": "FilterableEmbeddable" } ], "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", @@ -593,6 +601,48 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.getFilters", + "type": "Function", + "tags": [], + "label": "getFilters", + "description": [ + "\nGets the Lens embeddable's local filters" + ], + "signature": [ + "() => Promise<", + "Filter", + "[]>" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "children": [], + "returnComment": [ + "Local/panel-level array of filters for Lens embeddable" + ] + }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.getQuery", + "type": "Function", + "tags": [], + "label": "getQuery", + "description": [ + "\nGets the Lens embeddable's local query" + ], + "signature": [ + "() => Promise<", + "Query", + " | undefined>" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "children": [], + "returnComment": [ + "Local/panel-level query for Lens embeddable" + ] + }, { "parentPluginId": "lens", "id": "def-public.Embeddable.getSavedVis", diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 00fb0f1fbca999..b5cdbe2f8e0026 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibLensPluginApi slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github -summary: API docs for the lens plugin +description: API docs for the lens plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import lensObj from './lens.devdocs.json'; @@ -18,7 +21,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 611 | 0 | 529 | 40 | +| 613 | 0 | 529 | 40 | ## Client diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index fe15f80ede6f78..dfca23cc6b89f1 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibLicenseApiGuardPluginApi slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github -summary: API docs for the licenseApiGuard plugin +description: API docs for the licenseApiGuard plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 4f3ca21b59ae6a..d6e596284b4be7 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibLicenseManagementPluginApi slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github -summary: API docs for the licenseManagement plugin +description: API docs for the licenseManagement plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 67265e266c821a..69a98e45ab01b4 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibLicensingPluginApi slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github -summary: API docs for the licensing plugin +description: API docs for the licensing plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 0979a5b708ff8e..6f6a713fccf393 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibListsPluginApi slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github -summary: API docs for the lists plugin +description: API docs for the lists plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 0ed65db0d4f127..3789aee2b48445 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibManagementPluginApi slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github -summary: API docs for the management plugin +description: API docs for the management plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.devdocs.json b/api_docs/maps.devdocs.json index adf14e6907d43b..26f459392cbd9d 100644 --- a/api_docs/maps.devdocs.json +++ b/api_docs/maps.devdocs.json @@ -202,7 +202,14 @@ "MapByValueInput", ", ", "MapByReferenceInput", - ">" + ">,", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.FilterableEmbeddable", + "text": "FilterableEmbeddable" + } ], "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", "deprecated": false, @@ -453,6 +460,44 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable.getFilters", + "type": "Function", + "tags": [], + "label": "getFilters", + "description": [ + "\nTODO: Implement this function once https://github.com/elastic/kibana/issues/91282 is resolved" + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "deprecated": false, + "children": [], + "returnComment": [ + "[]" + ] + }, + { + "parentPluginId": "maps", + "id": "def-public.MapEmbeddable.getQuery", + "type": "Function", + "tags": [], + "label": "getQuery", + "description": [ + "\nTODO: Implement this function once https://github.com/elastic/kibana/issues/91282 is resolved" + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/maps/public/embeddable/map_embeddable.tsx", + "deprecated": false, + "children": [], + "returnComment": [ + "undefined" + ] + }, { "parentPluginId": "maps", "id": "def-public.MapEmbeddable.supportedTriggers", diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 6829a216fe116e..9de211601a3891 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibMapsPluginApi slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github -summary: API docs for the maps plugin +description: API docs for the maps plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import mapsObj from './maps.devdocs.json'; @@ -18,7 +21,7 @@ Contact [GIS](https://github.com/orgs/elastic/teams/kibana-gis) for questions re | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 253 | 0 | 252 | 25 | +| 255 | 0 | 252 | 25 | ## Client diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index d7a63f3d34ee76..99e693e6160056 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibMapsEmsPluginApi slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github -summary: API docs for the mapsEms plugin +description: API docs for the mapsEms plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 9516946b4ce9e7..5470d8326c26b5 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibMlPluginApi slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github -summary: API docs for the ml plugin +description: API docs for the ml plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 92a65a43a06596..5712651c5b808c 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibMonitoringPluginApi slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github -summary: API docs for the monitoring plugin +description: API docs for the monitoring plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 164e2cf2e4552c..6783b2f7077fb7 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibMonitoringCollectionPluginApi slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github -summary: API docs for the monitoringCollection plugin +description: API docs for the monitoringCollection plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 88649fac257267..4ee35bbab92217 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibNavigationPluginApi slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github -summary: API docs for the navigation plugin +description: API docs for the navigation plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index e3d0f4030217b1..de80bf283768fc 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibNewsfeedPluginApi slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github -summary: API docs for the newsfeed plugin +description: API docs for the newsfeed plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 2fef46534e32c1..711e70128c2a78 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibObservabilityPluginApi slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github -summary: API docs for the observability plugin +description: API docs for the observability plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 0662d95a4578d4..cc3819b5faa462 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibOsqueryPluginApi slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github -summary: API docs for the osquery plugin +description: API docs for the osquery plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 8739896158d988..2e699562a88e94 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -1,28 +1,31 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory -summary: Directory of public APIs available through plugins or packages. +description: Directory of public APIs available through plugins or packages. date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- ### Overall stats -| Count | Plugins or Packages with a
public API | Number of teams | +| Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| | 401 | 335 | 36 | ### Public API health stats -| API Count | Any Count | Missing comments | Missing exports | +| API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 28869 | 175 | 19603 | 911 | +| 28894 | 175 | 19605 | 911 | ## Plugin Directory -| Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | +| Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 266 | 0 | 261 | 19 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 23 | 0 | 19 | 1 | @@ -41,7 +44,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2524 | 2 | 296 | 6 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 102 | 0 | 83 | 1 | -| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 143 | 0 | 141 | 12 | +| | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 146 | 0 | 141 | 12 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 52 | 0 | 51 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3100 | 34 | 2421 | 22 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 15 | 0 | 7 | 0 | @@ -52,7 +55,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 10 | 0 | 8 | 2 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 84 | 0 | 68 | 7 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds embeddables service to Kibana | 507 | 0 | 413 | 4 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds embeddables service to Kibana | 512 | 0 | 413 | 4 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Extends embeddable plugin with more functionality | 14 | 0 | 14 | 0 | | | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 51 | 0 | 42 | 0 | | | [Enterprise Search](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 6 | 0 | 6 | 0 | @@ -95,14 +98,14 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | kibanaUsageCollection | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 0 | 0 | 0 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 615 | 3 | 420 | 9 | | | [Security Team](https://github.com/orgs/elastic/teams/security-team) | - | 3 | 0 | 3 | 1 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 611 | 0 | 529 | 40 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 613 | 0 | 529 | 40 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 8 | 0 | 8 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 3 | 0 | 3 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 10 | | | [Security detections response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 202 | 0 | 90 | 49 | | logstash | [Logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 41 | 0 | 41 | 6 | -| | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 253 | 0 | 252 | 25 | +| | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 255 | 0 | 252 | 25 | | | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 67 | 0 | 67 | 0 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 244 | 9 | 71 | 30 | | | [Stack Monitoring](https://github.com/orgs/elastic/teams/stack-monitoring-ui) | - | 11 | 0 | 9 | 1 | @@ -146,7 +149,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 428 | 0 | 407 | 46 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds UI Actions service to Kibana | 130 | 0 | 91 | 11 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Extends UI Actions plugin with more functionality | 205 | 0 | 142 | 9 | -| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 97 | 2 | 84 | 16 | +| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 108 | 2 | 84 | 16 | | upgradeAssistant | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | urlDrilldown | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds drilldown implementations to Kibana | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 12 | 0 | 12 | 0 | @@ -170,7 +173,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex ## Package Directory -| Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | +| Package name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [Owner missing] | Elastic APM trace data generator | 74 | 0 | 74 | 11 | | | [Owner missing] | - | 11 | 5 | 11 | 0 | @@ -338,7 +341,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 458 | 1 | 446 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 61 | 0 | 32 | 0 | | | [Owner missing] | io ts utilities and types to be shared with plugins from the security solution project | 28 | 0 | 21 | 0 | -| | [Owner missing] | security solution list REST API | 59 | 0 | 58 | 0 | +| | [Owner missing] | security solution list REST API | 61 | 0 | 60 | 0 | | | [Owner missing] | security solution list constants to use across plugins such lists, security_solution, cases, etc... | 26 | 0 | 12 | 0 | | | [Owner missing] | Security solution list ReactJS hooks | 56 | 0 | 44 | 0 | | | [Owner missing] | security solution list utilities | 235 | 0 | 187 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 3aa8398b740c47..c725267023db6b 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibPresentationUtilPluginApi slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github -summary: API docs for the presentationUtil plugin +description: API docs for the presentationUtil plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 6f0cd82e1a78ed..7c776acb7a4acf 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibRemoteClustersPluginApi slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github -summary: API docs for the remoteClusters plugin +description: API docs for the remoteClusters plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 5afca34982f27f..1d388b3acfd968 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibReportingPluginApi slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github -summary: API docs for the reporting plugin +description: API docs for the reporting plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index bc77cfd91dcbb3..0bd9a91a26f27a 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibRollupPluginApi slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github -summary: API docs for the rollup plugin +description: API docs for the rollup plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 6c8d83bc987387..1dde2c1cbe7ec7 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibRuleRegistryPluginApi slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github -summary: API docs for the ruleRegistry plugin +description: API docs for the ruleRegistry plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index a5ee7c49d14519..360f82253584fc 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibRuntimeFieldsPluginApi slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github -summary: API docs for the runtimeFields plugin +description: API docs for the runtimeFields plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 130c38292d30bb..eaad5a38e764e0 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSavedObjectsPluginApi slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github -summary: API docs for the savedObjects plugin +description: API docs for the savedObjects plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 668ccd3daae200..616f2d248b99db 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSavedObjectsManagementPluginApi slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github -summary: API docs for the savedObjectsManagement plugin +description: API docs for the savedObjectsManagement plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 4685825e7a6cd5..66f1a309ae95e7 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSavedObjectsTaggingPluginApi slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github -summary: API docs for the savedObjectsTagging plugin +description: API docs for the savedObjectsTagging plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 76f90c0802efce..ea4292a8be9fec 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSavedObjectsTaggingOssPluginApi slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github -summary: API docs for the savedObjectsTaggingOss plugin +description: API docs for the savedObjectsTaggingOss plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 16d10745203e92..c23865fe6c1d8d 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibScreenshotModePluginApi slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github -summary: API docs for the screenshotMode plugin +description: API docs for the screenshotMode plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 86e79999b384dd..38e37a57297ac3 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibScreenshottingPluginApi slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github -summary: API docs for the screenshotting plugin +description: API docs for the screenshotting plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index f8511044a4fca7..0f1f244cca7539 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSecurityPluginApi slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github -summary: API docs for the security plugin +description: API docs for the security plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index c7482d78f41f7b..bf4cfbe7d6773a 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSecuritySolutionPluginApi slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github -summary: API docs for the securitySolution plugin +description: API docs for the securitySolution plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 4ca297f594c7a2..ef3765cb5cbdbf 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSessionViewPluginApi slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github -summary: API docs for the sessionView plugin +description: API docs for the sessionView plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index b753451bb6e4bb..88fba9c1423d71 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSharePluginApi slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github -summary: API docs for the share plugin +description: API docs for the share plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/shared_u_x.mdx b/api_docs/shared_u_x.mdx index 8a6d39f05d426a..ba776dc1aab54b 100644 --- a/api_docs/shared_u_x.mdx +++ b/api_docs/shared_u_x.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSharedUXPluginApi slug: /kibana-dev-docs/api/sharedUX title: "sharedUX" image: https://source.unsplash.com/400x175/?github -summary: API docs for the sharedUX plugin +description: API docs for the sharedUX plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sharedUX'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import sharedUXObj from './shared_u_x.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index caeac63ee507a4..edafdb77df9887 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSnapshotRestorePluginApi slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github -summary: API docs for the snapshotRestore plugin +description: API docs for the snapshotRestore plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index f5ebf550fc41b4..022171ffab0b1c 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibSpacesPluginApi slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github -summary: API docs for the spaces plugin +description: API docs for the spaces plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 10fa21f771ae18..5ebc1265589139 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibStackAlertsPluginApi slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github -summary: API docs for the stackAlerts plugin +description: API docs for the stackAlerts plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index de967da0a364b3..499e2c1ba6159a 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTaskManagerPluginApi slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github -summary: API docs for the taskManager plugin +description: API docs for the taskManager plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index c60df09c546fb2..126aed02dcf61a 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTelemetryPluginApi slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github -summary: API docs for the telemetry plugin +description: API docs for the telemetry plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index cf79719b392967..88fe2b5ab9fc0b 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTelemetryCollectionManagerPluginApi slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github -summary: API docs for the telemetryCollectionManager plugin +description: API docs for the telemetryCollectionManager plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index ecd2f8c6086e37..524444d0e60975 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTelemetryCollectionXpackPluginApi slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github -summary: API docs for the telemetryCollectionXpack plugin +description: API docs for the telemetryCollectionXpack plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 1a53259103f894..d2317459c5a361 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTelemetryManagementSectionPluginApi slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github -summary: API docs for the telemetryManagementSection plugin +description: API docs for the telemetryManagementSection plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index cfc255dfe62c6a..94092d1733e78c 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibThreatIntelligencePluginApi slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github -summary: API docs for the threatIntelligence plugin +description: API docs for the threatIntelligence plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 85bb399795ea79..c0cd8214be0109 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTimelinesPluginApi slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github -summary: API docs for the timelines plugin +description: API docs for the timelines plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 0a2bf3dbb972d7..b78abc940d4876 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTransformPluginApi slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github -summary: API docs for the transform plugin +description: API docs for the transform plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index d8516da231894b..87808996d7c281 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibTriggersActionsUiPluginApi slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github -summary: API docs for the triggersActionsUi plugin +description: API docs for the triggersActionsUi plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 0af35abc19f93d..3856b6f83f1f8d 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUiActionsPluginApi slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github -summary: API docs for the uiActions plugin +description: API docs for the uiActions plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 922a3ab74839d1..60b1aba21badef 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUiActionsEnhancedPluginApi slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github -summary: API docs for the uiActionsEnhanced plugin +description: API docs for the uiActionsEnhanced plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index 42f2de80c78122..756a40fd1398ad 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -75,7 +75,9 @@ "type": "Function", "tags": [], "label": "FilterItem", - "description": [], + "description": [ + "\nRenders a single filter pill" + ], "signature": [ "(props: ", "FilterItemProps", @@ -102,13 +104,80 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItems", + "type": "Function", + "tags": [], + "label": "FilterItems", + "description": [ + "\nRenders a group of filter pills" + ], + "signature": [ + "(props: Pick<", + { + "pluginId": "unifiedSearch", + "scope": "public", + "docId": "kibUnifiedSearchPluginApi", + "section": "def-public.FilterItemsProps", + "text": "FilterItemsProps" + }, + ", \"filters\" | \"indexPatterns\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes, any, any>>) => JSX.Element" + ], + "path": "src/plugins/unified_search/public/filter_bar/index.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItems.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "unifiedSearch", + "scope": "public", + "docId": "kibUnifiedSearchPluginApi", + "section": "def-public.FilterItemsProps", + "text": "FilterItemsProps" + }, + ", \"filters\" | \"indexPatterns\" | \"readOnly\" | \"onFiltersUpdated\" | \"hiddenPanelOptions\" | \"timeRangeForSuggestionsOverride\"> & React.RefAttributes, any, any>>" + ], + "path": "src/plugins/unified_search/public/filter_bar/index.tsx", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "unifiedSearch", "id": "def-public.FilterLabel", "type": "Function", "tags": [], "label": "FilterLabel", - "description": [], + "description": [ + "\nRenders the label for a single filter pill" + ], "signature": [ "(props: ", "FilterLabelProps", @@ -555,6 +624,155 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps", + "type": "Interface", + "tags": [], + "label": "FilterItemsProps", + "description": [ + "\nProperties for the filter items component, which will render a single filter pill for every filter that is sent in\nas part of the `Filter[]` property." + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.filters", + "type": "Array", + "tags": [], + "label": "filters", + "description": [ + "Array of filters that will be rendered as filter pills" + ], + "signature": [ + "Filter", + "[]" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.readOnly", + "type": "CompoundType", + "tags": [], + "label": "readOnly", + "description": [ + "Optional property that controls whether or not clicking the filter pill opens a popover *and* whether\nor not the `x` button to remove the filter is rendered." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.onFiltersUpdated", + "type": "Function", + "tags": [], + "label": "onFiltersUpdated", + "description": [ + "If not read only, this is called whenever a filter is removed and/or updated" + ], + "signature": [ + "((filters: ", + "Filter", + "[]) => void) | undefined" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false, + "children": [ + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.onFiltersUpdated.$1", + "type": "Array", + "tags": [], + "label": "filters", + "description": [], + "signature": [ + "Filter", + "[]" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.indexPatterns", + "type": "Array", + "tags": [], + "label": "indexPatterns", + "description": [ + "A list of all dataviews that are used for the filters" + ], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.intl", + "type": "Object", + "tags": [], + "label": "intl", + "description": [ + "This is injected by the lazer loader" + ], + "signature": [ + "ReactIntl.InjectedIntl" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.timeRangeForSuggestionsOverride", + "type": "CompoundType", + "tags": [], + "label": "timeRangeForSuggestionsOverride", + "description": [ + "Controls whether or not filter suggestions are influenced by the global time" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.FilterItemsProps.hiddenPanelOptions", + "type": "Array", + "tags": [], + "label": "hiddenPanelOptions", + "description": [ + "Array of panel options that controls the styling of each filter pill" + ], + "signature": [ + "FilterPanelOption", + "[] | undefined" + ], + "path": "src/plugins/unified_search/public/filter_bar/filter_item/filter_items.tsx", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "unifiedSearch", "id": "def-public.QueryStringInputProps", diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 97b843cc9dde3d..cd19b426b03cc6 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUnifiedSearchPluginApi slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github -summary: API docs for the unifiedSearch plugin +description: API docs for the unifiedSearch plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import unifiedSearchObj from './unified_search.devdocs.json'; @@ -18,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 97 | 2 | 84 | 16 | +| 108 | 2 | 84 | 16 | ## Client diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index e412a8083cf9ac..0041ebcf3b648a 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUnifiedSearchAutocompletePluginApi slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github -summary: API docs for the unifiedSearch.autocomplete plugin +description: API docs for the unifiedSearch.autocomplete plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; @@ -18,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 97 | 2 | 84 | 16 | +| 108 | 2 | 84 | 16 | ## Client diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index cc52631ac135ab..4da6bca6a24f97 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUrlForwardingPluginApi slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github -summary: API docs for the urlForwarding plugin +description: API docs for the urlForwarding plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index e128db53581e2d..62fa454f4f1dc2 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUsageCollectionPluginApi slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github -summary: API docs for the usageCollection plugin +description: API docs for the usageCollection plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index b6ffdcec694e3b..afe4d8d90190c5 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibUxPluginApi slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github -summary: API docs for the ux plugin +description: API docs for the ux plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 7c22d241bd58e4..75f3dbbc40c14f 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisDefaultEditorPluginApi slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visDefaultEditor plugin +description: API docs for the visDefaultEditor plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 9b11dd3d5a4c72..2a89261e8dc1a6 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeGaugePluginApi slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeGauge plugin +description: API docs for the visTypeGauge plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 74c7d1b717ada6..38be595eae2a1a 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeHeatmapPluginApi slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeHeatmap plugin +description: API docs for the visTypeHeatmap plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index f71e3f56485625..4db7c9d4278748 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypePiePluginApi slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypePie plugin +description: API docs for the visTypePie plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 41a117811917b6..fe4ff96047f953 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeTablePluginApi slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeTable plugin +description: API docs for the visTypeTable plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 36444e9743320d..20b08f1f326189 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeTimelionPluginApi slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeTimelion plugin +description: API docs for the visTypeTimelion plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index e9a30d09425959..dba13175c35be1 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeTimeseriesPluginApi slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeTimeseries plugin +description: API docs for the visTypeTimeseries plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index f30de804741fc3..7be4ffb5296b4a 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeVegaPluginApi slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeVega plugin +description: API docs for the visTypeVega plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 28ed93c1531bfc..7885c843e68bb8 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeVislibPluginApi slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeVislib plugin +description: API docs for the visTypeVislib plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 8f0bc09bcb5394..aab476edc42b94 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisTypeXyPluginApi slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visTypeXy plugin +description: API docs for the visTypeXy plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index 62b7651579dc5b..4752d972ce2708 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -5157,7 +5157,11 @@ "section": "def-public.ContainerOutput", "text": "ContainerOutput" }, - "> | undefined; updateInput: (changes: Partial<", + "> | undefined; getQuery: () => Promise<", + "Query", + " | ", + "AggregateQuery", + " | undefined>; updateInput: (changes: Partial<", { "pluginId": "visualizations", "scope": "public", @@ -5165,7 +5169,9 @@ "section": "def-public.VisualizeInput", "text": "VisualizeInput" }, - ">) => void; reportsEmbeddableLoad: () => boolean; getInspectorAdapters: () => ", + ">) => void; reportsEmbeddableLoad: () => boolean; getFilters: () => Promise<", + "Filter", + "[]>; getInspectorAdapters: () => ", { "pluginId": "inspector", "scope": "common", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 12a8c58e18e10a..b8a849ec5ea8da 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -1,12 +1,15 @@ --- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### id: kibVisualizationsPluginApi slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github -summary: API docs for the visualizations plugin +description: API docs for the visualizations plugin date: 2022-08-10 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] -warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- import visualizationsObj from './visualizations.devdocs.json'; From 1bab5775e3d4bca888fb2e1b43bd29771f6942e4 Mon Sep 17 00:00:00 2001 From: Andrew Tate Date: Wed, 10 Aug 2022 18:59:31 -0500 Subject: [PATCH 05/59] reuse frame public API selector (#138430) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/state_management/lens_slice.ts | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/lens/public/state_management/lens_slice.ts b/x-pack/plugins/lens/public/state_management/lens_slice.ts index 2a71cd9aaab48a..14510a47b9d1da 100644 --- a/x-pack/plugins/lens/public/state_management/lens_slice.ts +++ b/x-pack/plugins/lens/public/state_management/lens_slice.ts @@ -11,7 +11,6 @@ import { mapValues } from 'lodash'; import { Query } from '@kbn/es-query'; import { History } from 'history'; import { LensEmbeddableInput } from '..'; -import { getDatasourceLayers } from '../editor_frame_service/editor_frame'; import { TableInspectorAdapter } from '../editor_frame_service/types'; import type { VisualizeEditorContext, Suggestion } from '../types'; import { getInitialDatasourceId, getResolvedDateRange, getRemoveOperation } from '../utils'; @@ -22,6 +21,7 @@ import type { LayerType } from '../../common/types'; import { getLayerType } from '../editor_frame_service/editor_frame/config_panel/add_layer'; import { getVisualizeFieldSuggestions } from '../editor_frame_service/editor_frame/suggestion_helpers'; import { FramePublicAPI, LensEditContextMapping, LensEditEvent } from '../types'; +import { selectFramePublicAPI } from './selectors'; export const initialState: LensAppState = { persistedDoc: undefined, @@ -628,14 +628,7 @@ export const makeLensReducer = (storeDeps: LensStoreDeps) => { layerType ); - const framePublicAPI = { - // any better idea to avoid `as`? - activeData: state.activeData - ? (current(state.activeData) as TableInspectorAdapter) - : undefined, - datasourceLayers: getDatasourceLayers(state.datasourceStates, datasourceMap), - dateRange: current(state.resolvedDateRange), - }; + const framePublicAPI = selectFramePublicAPI({ lens: current(state) }, datasourceMap); const activeDatasource = datasourceMap[state.activeDatasourceId]; const { noDatasource } = @@ -687,14 +680,7 @@ export const makeLensReducer = (storeDeps: LensStoreDeps) => { const { activeDatasourceState, activeVisualizationState } = addInitialValueIfAvailable({ datasourceState: state.datasourceStates[state.activeDatasourceId].state, visualizationState: state.visualization.state, - framePublicAPI: { - // any better idea to avoid `as`? - activeData: state.activeData - ? (current(state.activeData) as TableInspectorAdapter) - : undefined, - datasourceLayers: getDatasourceLayers(state.datasourceStates, datasourceMap), - dateRange: current(state.resolvedDateRange), - }, + framePublicAPI: selectFramePublicAPI({ lens: current(state) }, datasourceMap), activeVisualization, activeDatasource, layerId, From c890ca024215d7f96002a47ab1f96de0fc556e85 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 11 Aug 2022 00:40:56 -0400 Subject: [PATCH 06/59] [api-docs] Daily api_docs build (#138590) --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/core.mdx | 2 +- api_docs/core_application.mdx | 2 +- api_docs/core_chrome.mdx | 2 +- api_docs/core_saved_objects.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 2 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/elastic_apm_synthtrace.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/fleet.mdx | 2 +- api_docs/global_search.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- api_docs/kbn_alerts.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx | 2 +- api_docs/kbn_analytics_shippers_elastic_v3_common.mdx | 2 +- api_docs/kbn_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bazel_packages.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- api_docs/kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- api_docs/kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- api_docs/kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- api_docs/kbn_core_deprecations_browser_internal.mdx | 2 +- api_docs/kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_client_server_internal.mdx | 2 +- api_docs/kbn_core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- api_docs/kbn_core_elasticsearch_server_internal.mdx | 2 +- api_docs/kbn_core_elasticsearch_server_mocks.mdx | 2 +- api_docs/kbn_core_environment_server_internal.mdx | 2 +- api_docs/kbn_core_environment_server_mocks.mdx | 2 +- api_docs/kbn_core_execution_context_browser.mdx | 2 +- api_docs/kbn_core_execution_context_browser_internal.mdx | 2 +- api_docs/kbn_core_execution_context_browser_mocks.mdx | 2 +- api_docs/kbn_core_execution_context_common.mdx | 2 +- api_docs/kbn_core_execution_context_server.mdx | 2 +- api_docs/kbn_core_execution_context_server_internal.mdx | 2 +- api_docs/kbn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- api_docs/kbn_core_http_context_server_mocks.mdx | 2 +- api_docs/kbn_core_http_router_server_internal.mdx | 2 +- api_docs/kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- api_docs/kbn_core_injected_metadata_browser.mdx | 2 +- api_docs/kbn_core_injected_metadata_browser_mocks.mdx | 2 +- api_docs/kbn_core_integrations_browser_internal.mdx | 2 +- api_docs/kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_collectors_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- api_docs/kbn_core_mount_utils_browser_internal.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- api_docs/kbn_core_notifications_browser_internal.mdx | 2 +- api_docs/kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- api_docs/kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_api_browser.mdx | 2 +- api_docs/kbn_core_saved_objects_api_server.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- api_docs/kbn_core_saved_objects_browser_internal.mdx | 2 +- api_docs/kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- api_docs/kbn_core_test_helpers_deprecations_getters.mdx | 2 +- api_docs/kbn_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_internal.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- api_docs/kbn_core_ui_settings_browser_internal.mdx | 2 +- api_docs/kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_get_repo_files.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_kibana_manifest_parser.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- api_docs/kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_alerting_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- api_docs/kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_components.mdx | 2 +- api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_analytics_no_data.mdx | 2 +- api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_kibana_no_data.mdx | 2 +- api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- api_docs/kbn_shared_ux_prompt_no_data_views.mdx | 2 +- api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_services.mdx | 2 +- api_docs/kbn_shared_ux_storybook.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_package_json.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_type_summarizer.mdx | 2 +- api_docs/kbn_type_summarizer_core.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/plugin_directory.mdx | 2 +- api_docs/presentation_util.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/shared_u_x.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 345 files changed, 345 insertions(+), 345 deletions(-) diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index d9debf86126342..f282d76f832a9f 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index d48c56ee4ba3b9..d2ceaab33973da 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 9b2bc406330fb2..187f9343d71c4b 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 0b79758b2bca5c..dc6b0afa761ed0 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index c775ed9f7c780b..7300c7c4e6e798 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 692c4c49903118..0b0ed7407957d0 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 5fa356ed6b1a6c..d69a594d888e18 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index b99bcdf1047f9b..e7815d47682eeb 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 9f89af0916e15c..303a1b51161d52 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 3ca08a5cf52800..2f719228ffca3c 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 75d33bb6cb38d4..92fb236da4dfe3 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 73d38c0501fbeb..3187f3c79b136e 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 82eb9a8b5ffde3..c8fa214ebb827c 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 75b8f870d8d07a..3bf15c15f0ecf1 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/core.mdx b/api_docs/core.mdx index de7ed5719a1a06..3574957c8e0fc1 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index 09667162a0bd57..c3589c46a04696 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-application title: "core.application" image: https://source.unsplash.com/400x175/?github description: API docs for the core.application plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.application'] --- import coreApplicationObj from './core_application.devdocs.json'; diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index 9cc2d6c8449d7b..7bace2a507a6c5 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-chrome title: "core.chrome" image: https://source.unsplash.com/400x175/?github description: API docs for the core.chrome plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.chrome'] --- import coreChromeObj from './core_chrome.devdocs.json'; diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index bab45e3b860fba..6fcd60f4851a4f 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-savedObjects title: "core.savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the core.savedObjects plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.savedObjects'] --- import coreSavedObjectsObj from './core_saved_objects.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index e6dcad20dee0cf..43bfe0acae3097 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 7a35aae0ec2c9b..e9b89abcc6115a 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index a71ee95fbed8e0..9e9e9022ad468b 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 75ba7f5d691a5b..e99dae2e55978a 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 5e69ab274ba188..e42c8927f38470 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 9e6a0466aea6e0..01c72585f1aa3d 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 0f8f87d96257aa..1e6e5291499893 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 86cd795dd7dfe0..b2581e4f922421 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 5581c953daad00..8d9911745c4d3e 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index f94248c3e21918..6bb7f9213f8898 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index a23db05ec0db5a..c779357745331b 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index b2797246ab652e..aa4ecef1c0dad4 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 1849ced937dcf7..40935bd3a4ec62 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index ed8f1ba63a87e9..55fe21009f1a01 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 17efa22d534490..13dad9769e26ac 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index f63dd0b8f2822d..d95e7b4b4ec074 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 1c7810999e8878..37520938fdd5a6 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/elastic_apm_synthtrace.mdx b/api_docs/elastic_apm_synthtrace.mdx index de6c6e8d257503..513b14bbf25b06 100644 --- a/api_docs/elastic_apm_synthtrace.mdx +++ b/api_docs/elastic_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elastic-apm-synthtrace title: "@elastic/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @elastic/apm-synthtrace plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-synthtrace'] --- import elasticApmSynthtraceObj from './elastic_apm_synthtrace.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index f45e061cd95ab3..c2980c7c90f924 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index b0d4d7c2c24cbf..4953a59facca60 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index a3914ef5316ce0..82db857f64353a 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 62c7b7ab7751f9..be1cc389b67f24 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 17c3fdf606766f..5985f4ac49506e 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index d6d19f9a65f71a..882ec361bdb708 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index daa352980179a2..169240a4e31f16 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 98a4a57dc96c8b..c26dd9d602518e 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 44d2ca5d3a562c..805db130b36354 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index e7f59d68e49542..6d4d4c5bc37973 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 60fb5ed4c81304..ccb91e5f51b846 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 3192942b7153ae..827dfeb0783b1f 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index df59a5ac851b5b..0fc049cd34fd88 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 418641075bcde2..d865c607d2a798 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 83ae6ccc351cb4..f376d7efbd3c04 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 4d0209cb49ae48..35cadf94820783 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index dd13abd47587a1..c4093b827de57f 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index f691e0f454935c..91c67dcaabba93 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index ff37e4d33a3815..44b99db0d35e3c 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index b36ba6f2ef3d5d..dffc2947568198 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 6107cfa5489977..5ce386f8a2f496 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index acb0acbe2b4c44..2393f30a5b9a02 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 48ea69722201ae..b90819ea8f5aa1 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 122761a52341f5..9d9e0eb35894c4 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index d566fb2abbed47..9bb727824c189b 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 75421786871619..33748702b61b8b 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 19ac48f638e66c..cd3147cc301bd0 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index b4c6de85363638..e828742670e19e 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index e671d6979edf36..c4d0c091519f77 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index bd982b44e15db0..58f393c23bc6f2 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index a6172213d301db..5b5f9f42f9bdcf 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index d4e8c0f6f9559d..76159a88a4046b 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 7bc465f202671d..ad13f5ee9c2d0f 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index e270cccdbb149e..d52a5f6b909c30 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index e24d06855e463c..149c07f9a66530 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 90a3d734258b5c..4e3fd64430fe4a 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index bd7fad52dade9d..441f3eb3db7416 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index ba5f94e88876c4..c1f06d561d0447 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 15be83106b1efc..d9fab71d985946 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index b4e0ad28d3c1e6..2201f02c575586 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index c17ff240d5799e..8e48be19e49b8e 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 1c1a422a1d3565..0f8b6675aa3b3c 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 3a38ca144894ca..6ee6654bca6279 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index f10d2d189fc2b8..552bd53fc92307 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 2c818293025947..5511c5405411fa 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bazel_packages.mdx b/api_docs/kbn_bazel_packages.mdx index 9b4470a79410ea..3f72ba8df808af 100644 --- a/api_docs/kbn_bazel_packages.mdx +++ b/api_docs/kbn_bazel_packages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bazel-packages title: "@kbn/bazel-packages" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bazel-packages plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-packages'] --- import kbnBazelPackagesObj from './kbn_bazel_packages.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 55bc3cd497ae9c..e000823006bae0 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 97ab51ff028ad3..b4c7822027657a 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 59fbf29bda0bb2..124fdda39cd951 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 25397ce8c1b2ba..a4432f832ef5e2 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 623658e117bc75..ae5cd47cda8166 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 30cbc67ed778a0..2d89d9f9d3d278 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index 6ac320fb200733..fc93f0c95c25df 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 7fedf6ba97cc93..3f692e8c39e74f 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 38c12fdfc2a3ae..dc25d37e8dcb60 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 0cb2fad42af347..6ed61554c64dc3 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 59ed1073c527d0..083459d82e7349 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 557a5d3aa9b51b..eabbc9e8244607 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 9292a1959f45cd..e85565987a37e7 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 478dc44f58fb5a..2e7d30f0d0fbf6 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 2a213e335029f6..34de7d4b8e06ac 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 0cab7dd6adc34f..573b7df56d3c32 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 1b790a3aa7fa63..18e83415fc77b1 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index b5b479b107bff8..90308821b16024 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 14dd1e84c9933a..5c9813c841e937 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index db5d0f23b0558f..2d74140d25d5be 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 2d14bcb7fee9a6..5864db03de0713 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 89cf6d938e32f4..980aeb7e5eafd1 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 3b9fc2f3630f57..c7b4f1f1db12ea 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index d85d12d177bfcb..b51f5542dcac56 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index ebe495b965b47c..ae1d2d010d9ce6 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index b1dcc85409acb6..ef822626f6f334 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 2ee5b745daa87f..5b70ecb0321513 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index d217f9f349cfbe..c153294c409c34 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 7666fab1b2d457..5bb7687740ecf0 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 1e2b1c3cd2ef18..2cd86fe9ad73bb 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index a7a12a761133ef..ed0b4b1c9bcfdf 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index c5b167a12681a5..2bb6fd38a54867 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 59400ce18d9a84..f5f44e819ce927 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index adf8c71f58e607..fcb6bee1f95ca9 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 18bc9b36455909..0b469954356942 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index e8a70ce60c7d5e..10f74250c8dd0b 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index a36ff455ffc242..b84b68e017374d 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 11cbc9dac48fc3..1f6edae3523a87 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 0deb55eae32e75..400b5a8cd8d618 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 9f089a48f97ba4..5756f10d510006 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 782d1fb88e738f..1775cf95424b56 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 1d9901d9ff0c6c..0fbd1783b6c313 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 18a8e96fe0bea4..b80f7f7829f3ff 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index e513446b139369..5894717106f89b 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 08e7d29db6a114..788d6e2d1202f6 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 41f541d1c27c9d..b21295fde28b6e 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 539d5ea5677787..4c0375f75ef49d 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 5b760bfab34ea3..741b7b15181ede 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index bfedc44dd4d9ab..7a748adae2e2bd 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 9bcce94ced59db..c2ced4707e7e2d 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index a9ec3d9417ed8c..a450f828cc24b8 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index f3c6a235da96bc..660e16aaa23345 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index ebadcfbaf2c389..281c9400435f23 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index d916e2de8c61ae..6736f3e83167d2 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 09e6fbd78f3b16..c82bdcaec983f3 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index ea492eafc4150e..dc7f6893d73970 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 9c5ba3d8b049f9..29a450346c4469 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index c062fc2ef85d88..0345e27a252c4c 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 2bc83f827cb968..104d153f003fec 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 1ca36d6871b75b..23d3b5fd4460ea 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 5d2be3bd28bf80..8f36ee7e2ce4d2 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index a5fd5222f6ff4d..8569ab0f0bb05a 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 9c3429d1827fbb..ca4ceef547462a 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 5c6fa6ce48ba53..aacfe4c584c299 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 71041214955905..39dbbf64c899a6 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index e7a96d9e147598..1362bd713e36e4 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 7e3f3a73ae2bf3..71bc6f3a3f04a4 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index d8421002909feb..041ef87b429526 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 56679c0fac4f0c..ae16ec053bb116 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 4e2f78e552fc7f..b4a898c163d5a2 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 4001305370246a..ae5b022c353d8f 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser_internal.mdx b/api_docs/kbn_core_mount_utils_browser_internal.mdx index 554db464654d46..31eef32ff122da 100644 --- a/api_docs/kbn_core_mount_utils_browser_internal.mdx +++ b/api_docs/kbn_core_mount_utils_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser-internal title: "@kbn/core-mount-utils-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser-internal'] --- import kbnCoreMountUtilsBrowserInternalObj from './kbn_core_mount_utils_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 6fa8989f9a54a9..46bc2f98e711d2 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index e1db2b6fc239bc..32bdf17e3702da 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index f054ee9e74e994..1c237f65329ecc 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index ed28d6e8607ccd..2f29364b23a433 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 6c08452e5d9364..7616c2e3e5d19a 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index bcf616f60134bb..0fcdf7624cf5b3 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 78fad3316f0d71..453c38659a5e4d 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index d941741e1979ef..a34142a2fae29a 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index a16317e25c60b6..37408d1a0c8e00 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index f87449e4a77ce4..9a7c7a1edce558 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 4ee9f89ec3c67e..0afd2e4c96dea5 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 7296fba5302cb0..f4c2d6f9ccc42c 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index e2f0a1749d5aad..8fc0b694aa6c1e 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index b18ef02e32332a..24b3e5da37fbbd 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 47c87c5e56e1ec..032339de4038f4 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 4ca709a50337cc..038b770a93bac6 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index c3cc2b35596314..1d5aaa46503482 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index f62f25d45463f6..52b21777a44360 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 62df59fe050ff4..787255afdcef68 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index ff0e91cf1de85b..5324e74eaddf4a 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index c289959f201805..607691e3099a32 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index 0494aba943d853..d2d25970198faa 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index f55a4a41bf4933..dd78cb97c9b73c 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index c1a5d83063ad2e..319ea1a3816db5 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index ed55bfb684e318..dbf6c57f3a902f 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 181658c6e1ced1..6cd80192464350 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 12cba7495172e3..23df6c2264954d 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index fc4d3f1abd1c89..7d308692aa3d3c 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index b92c2d8d4e78ca..2880bdaed08ba3 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 8d5531e2226e29..b72576e13c035c 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 7e4b1ab51926df..d55689dd7adfaa 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index acd1f1bbf2b985..e2a3d8828c9de0 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 41dbafc0bc1fb1..43f9f57f375482 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 0da804e752f452..e92051ab7b1df1 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 0884a68cf4412a..c0c47f70125cd5 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 891ded77cf277d..7d67005ca5e99c 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index fd93fb141ce85b..baed6476694f03 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 0f807c0b43c12e..fb0b15352818bd 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 393ecd76d6e92e..3484f1a6ada512 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 1af39670b91094..eade19c03aa863 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 802105b6ab31fb..9a7b139bc2a523 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index d49b3b2f690ca7..e31c681e7ba4d7 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 61c6b87747f72c..188031bf41fcc6 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 4c540cb90dcd2a..a77e974d22f041 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index d1835b5faac093..8e464bd8f0012b 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 9b4017593eee69..72a4fe984177fb 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 9681a90d7fb4ec..2c309c2f64a286 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index fdac17540890ce..889d0c17237d9b 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index a261a5337cd520..956443176eec36 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 8aac8ce56d56e7..3b55fb665b7731 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index af416592c96f43..18cedf5f5e4f89 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index c1efe00dc76ff1..09163c26a680d8 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index eec1b4e9073ba0..bb1c0bedada868 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index f7f8667e78e972..20a4d28a0221ef 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_parser.mdx b/api_docs/kbn_kibana_manifest_parser.mdx index 03788cb327193a..8d12a00d7354ae 100644 --- a/api_docs/kbn_kibana_manifest_parser.mdx +++ b/api_docs/kbn_kibana_manifest_parser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-parser title: "@kbn/kibana-manifest-parser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-parser plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-parser'] --- import kbnKibanaManifestParserObj from './kbn_kibana_manifest_parser.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 03b946bd25a012..5f16371077c036 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 724ed4fd38fe2f..48d05d099c986d 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index b72734dffbc206..f3e37ddd2f7990 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index b049ef5d8a506b..cdcc007bda5475 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index dcd5593003f6af..71af48ec9a4dd1 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 5f4db6fe80f91f..4f3afabcbdf20f 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 02cc5334a886af..fd25d71911ac48 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 7d395d3a069a1b..84f80a8557221c 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 3a8cfb0d9e5546..2c037730f69efc 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 401ffa5b6df92f..99c81b283e5eb7 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 1433bed9a5223d..500fd91a654e36 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index d2547dbdf7c37a..84fe13cd647f3a 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 41377f5f936099..7a4b18b12d6f8d 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 4a00c6457c8b59..8fef2ea69e8fac 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 7b4165dea7145d..b03dc56faba874 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 1dc03a31b146fc..55d597dc0f2a91 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index c99d36d31674a1..65475404e39084 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 01381b9c64531f..0eb32869202449 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index b86f2b37fb312f..3fd73ca86c922a 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 64447548f7b9db..059651e0c5a5a6 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 8021d578650f97..7f4324a0e17724 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 51c28cadb81b3a..985ca5901286b3 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 728f79e48e063f..4afc55fb373bad 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index f12bee7cba2f1f..5c756ed317cae8 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index b350cdb74f58a8..cfdfd9a6568c6a 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index c5982bc8047841..f2c6e31617cf89 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 47c226d31517a4..b25c0b1deb60d4 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 8e93c81a792c51..fcbcb384848c24 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 7784aac276bbbb..558fcb7778dc36 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index d19589e0fbf251..8d8bebe8fc2001 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 05c368a4a14a24..98a042e1ed2332 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 604e4759040936..a1ba58192aaa9a 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 40f966dda3f0ff..bce8de0772e484 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 990fad803c7c25..602b7900da2ca6 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 60b5b3d3306260..36fa3bff8a0568 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index fccebd49555583..5900fcefa5a239 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index d293d0de06b6c5..f9f761e93c106a 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index ab21403b9c618d..4b4a6a247c8b83 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_components.mdx b/api_docs/kbn_shared_ux_components.mdx index 2cd1cfaf5b8ccb..d69138c6435ae4 100644 --- a/api_docs/kbn_shared_ux_components.mdx +++ b/api_docs/kbn_shared_ux_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-components title: "@kbn/shared-ux-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-components plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-components'] --- import kbnSharedUxComponentsObj from './kbn_shared_ux_components.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 75fd35ae9d67c5..a4cc2d4b26bb12 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 1e6fc6e2ab71f6..25689321f7f8cd 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 016debf569b804..6fd9be7b546a09 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 1e0532f5aa87fd..5c4f74b5ad4fa6 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index ef904ec8a5a709..70ab9a10e94350 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index fa8e36b80886cf..bf61fc483d6c50 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 77afd07c333deb..8a24fe051e71a7 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 6ddacd28b576a1..bb254d68a98c3e 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_services.mdx b/api_docs/kbn_shared_ux_services.mdx index 385b93d1e9050d..bd1958f97749e6 100644 --- a/api_docs/kbn_shared_ux_services.mdx +++ b/api_docs/kbn_shared_ux_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-services title: "@kbn/shared-ux-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-services plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-services'] --- import kbnSharedUxServicesObj from './kbn_shared_ux_services.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook.mdx b/api_docs/kbn_shared_ux_storybook.mdx index 69abf887d35cec..a13e4cceb4d0c4 100644 --- a/api_docs/kbn_shared_ux_storybook.mdx +++ b/api_docs/kbn_shared_ux_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook title: "@kbn/shared-ux-storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook'] --- import kbnSharedUxStorybookObj from './kbn_shared_ux_storybook.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 97535d2c0a7e1c..49725a3f13e479 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index bae9f2e90952d9..364e61e82fd8a0 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 23b03700d87da6..7f40f129763d06 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index c1489a38ee153d..825cbae993202e 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 19636d8cf53e98..6bbc561c4830f1 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index bccf3025c5ba3b..1f6b56839503a1 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index a3ff88389f2a9e..d5c5ecd9710615 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index c9532fe53827d6..eb842010913da7 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 027f4d88932b25..81468659ef8d1c 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 8a3442c98e962a..218032a0205ceb 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 5127776b8be9ab..e04ac886039e93 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index 2664ecc3cff6c2..b93458fcfd6f3c 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index 7f7daf6d343d7d..09973a0355c1a7 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 2f6012dc105ea8..fc803c91fe2278 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index e98d12e5e580ca..0b8adb42b2510c 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 33d1d62a2807d6..49b6b5b49565de 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index b8c0a3eb58238a..53d0fa73d9ee07 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 71fcef1e0eaa03..bdecfc73f4ebc1 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 2742f05a406626..b546f76fbb408e 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 0cc04b1399123a..7b193b75ddcbc9 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 91d1b423874aa9..9b707bb0c7dcf3 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 10c2cf52b0b3e7..8c7f62aba14141 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index ef378071118f60..e56406b94b4c5e 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 9dd4e4953ae937..48713acc4b59ae 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index b5cdbe2f8e0026..79cab2a0c391be 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index dfca23cc6b89f1..aba6b167cae5a2 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index d6e596284b4be7..812fddd90eaa46 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 69a98e45ab01b4..5e24095c695cfb 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 6f6a713fccf393..650ae2c4029524 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 3789aee2b48445..bd6c4e20be181f 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 9de211601a3891..3b773461df2443 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 99e693e6160056..70e163489b0a0d 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 5470d8326c26b5..8e72f2881a7b40 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 5712651c5b808c..35d5950e9aa09a 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 6783b2f7077fb7..99444b3ab8c4f3 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 4ee35bbab92217..3e6e703b2627f5 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index de80bf283768fc..4c27826c7d70d1 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 711e70128c2a78..beb1f8ed4ce00b 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index cc3819b5faa462..932943299b4d5c 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 2e699562a88e94..5edc8ff33896b9 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index c725267023db6b..4941daae32dd95 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 7c776acb7a4acf..8d4396be9bf197 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 1d388b3acfd968..6aee86e0fdf60d 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 0bd9a91a26f27a..023133740bb35f 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 1dde2c1cbe7ec7..932775d59d1f86 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index 360f82253584fc..c8f4bbb7cfd547 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index eaad5a38e764e0..2a45acec975d7e 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 616f2d248b99db..5aedc341f2015e 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 66f1a309ae95e7..fcdc28e1902916 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index ea4292a8be9fec..b20c324fc17527 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index c23865fe6c1d8d..33de999c004878 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 38e37a57297ac3..8d5a646481901d 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 0f1f244cca7539..706e8aac915466 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index bf4cfbe7d6773a..21c98900020f08 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index ef3765cb5cbdbf..68180e90389959 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 88fba9c1423d71..b573d28030c720 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/shared_u_x.mdx b/api_docs/shared_u_x.mdx index ba776dc1aab54b..d6cfa154851886 100644 --- a/api_docs/shared_u_x.mdx +++ b/api_docs/shared_u_x.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sharedUX title: "sharedUX" image: https://source.unsplash.com/400x175/?github description: API docs for the sharedUX plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sharedUX'] --- import sharedUXObj from './shared_u_x.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index edafdb77df9887..d3d5e104f45260 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 022171ffab0b1c..9038d2eacc9088 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 5ebc1265589139..dcdba1552f10a7 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 499e2c1ba6159a..ce359ca4fd7b99 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 126aed02dcf61a..89a01c83122b2d 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 88fe2b5ab9fc0b..865e7be0c9551a 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 524444d0e60975..b4fa569dbc78be 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index d2317459c5a361..486de1a4c8432a 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 94092d1733e78c..f147d268825a28 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index c0cd8214be0109..b955620c88ff3d 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index b78abc940d4876..5f6c713dc50d3f 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 87808996d7c281..d55719923df333 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 3856b6f83f1f8d..375718734c27e7 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 60b1aba21badef..e651863ed5962b 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index cd19b426b03cc6..a5328347a36256 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 0041ebcf3b648a..d6b1410085d75d 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 4da6bca6a24f97..f1422e2da619e1 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 62fa454f4f1dc2..8c0738785659ab 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index afe4d8d90190c5..7b4f36876f174c 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 75f3dbbc40c14f..d1ca9c17993492 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 2a89261e8dc1a6..28f78831cc229b 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 38be595eae2a1a..50e7e19e267365 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 4db7c9d4278748..dc67a737d1e99e 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index fe4ff96047f953..f5d1e470e712b7 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 20b08f1f326189..078ba6536f657f 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index dba13175c35be1..9d18d6a2cb1290 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 7be4ffb5296b4a..3b572d668e70ea 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 7885c843e68bb8..f7cd6b727ef718 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index aab476edc42b94..45160066493f50 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index b8a849ec5ea8da..77bc2d77102e13 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2022-08-10 +date: 2022-08-11 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From 5dba80760b62d4e22003bc3f8a5bf3aee2e8746f Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 11 Aug 2022 08:14:26 +0200 Subject: [PATCH 07/59] increase timeout (#138536) --- x-pack/test/functional/page_objects/lens_page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 33d48321cfb8a2..2d9eff8fefd9cb 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -70,7 +70,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont async assertExpectedText(selector: string, test: (value?: string) => boolean) { let actualText: string | undefined; - await retry.waitForWithTimeout('assertExpectedText', 1000, async () => { + await retry.waitForWithTimeout('assertExpectedText', 5000, async () => { actualText = await find.byCssSelector(selector).then((el) => el.getVisibleText()); return test(actualText); }); From 9a1a963ae3ef30ec0d9c1476a1c76370bbfd0284 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 11 Aug 2022 10:51:51 +0200 Subject: [PATCH 08/59] [ML] Explain Log Rate Spikes: Basic functional tests. (#138387) Adds first functional tests for Explain Log Rate Spikes. The test clicks the menu item, selects an index, clicks the "Use full data" button and asserts the page's elements. --- .buildkite/ftr_configs.yml | 1 + .../explain_log_rate_spikes_page.tsx | 3 +- .../apis/aiops/explain_log_rate_spikes.ts | 2 +- .../test/api_integration/apis/aiops/index.ts | 2 +- .../api_integration_basic/apis/aiops/index.ts | 2 +- .../apis/aiops/permissions.ts | 2 +- x-pack/test/functional/apps/aiops/config.ts | 20 +++++ .../apps/aiops/explain_log_rate_spikes.ts | 87 +++++++++++++++++++ x-pack/test/functional/apps/aiops/index.ts | 38 ++++++++ .../test/functional/apps/aiops/test_data.ts | 17 ++++ x-pack/test/functional/apps/aiops/types.ts | 16 ++++ .../services/aiops/explain_log_rate_spikes.ts | 64 ++++++++++++++ .../test/functional/services/aiops/index.ts | 18 ++++ x-pack/test/functional/services/index.ts | 2 + .../services/ml/job_source_selection.ts | 4 + 15 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 x-pack/test/functional/apps/aiops/config.ts create mode 100644 x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts create mode 100644 x-pack/test/functional/apps/aiops/index.ts create mode 100644 x-pack/test/functional/apps/aiops/test_data.ts create mode 100644 x-pack/test/functional/apps/aiops/types.ts create mode 100644 x-pack/test/functional/services/aiops/explain_log_rate_spikes.ts create mode 100644 x-pack/test/functional/services/aiops/index.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 1d3ea8c5dd4d0e..3395b422e793d9 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -151,6 +151,7 @@ enabled: - x-pack/test/functional_synthetics/config.js - x-pack/test/functional_with_es_ssl/config.ts - x-pack/test/functional/apps/advanced_settings/config.ts + - x-pack/test/functional/apps/aiops/config.ts - x-pack/test/functional/apps/api_keys/config.ts - x-pack/test/functional/apps/apm/config.ts - x-pack/test/functional/apps/canvas/config.ts diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx index a6a2a6808dbaf2..3b0ad9ddfc2e60 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx @@ -171,7 +171,7 @@ export const ExplainLogRateSpikesPage: FC = ({ } return ( - + @@ -268,6 +268,7 @@ export const ExplainLogRateSpikesPage: FC = ({ />

} + data-test-subj="aiopsNoWindowParametersEmptyPrompt" /> )} diff --git a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts index 9261dc8b1bea97..00d3bc38a563ed 100644 --- a/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts +++ b/x-pack/test/api_integration/apis/aiops/explain_log_rate_spikes.ts @@ -12,7 +12,7 @@ import expect from '@kbn/expect'; import type { ApiExplainLogRateSpikes } from '@kbn/aiops-plugin/common/api'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import type { FtrProviderContext } from '../../ftr_provider_context'; import { parseStream } from './parse_stream'; diff --git a/x-pack/test/api_integration/apis/aiops/index.ts b/x-pack/test/api_integration/apis/aiops/index.ts index 24a0391cf4877d..f311f35a51f879 100644 --- a/x-pack/test/api_integration/apis/aiops/index.ts +++ b/x-pack/test/api_integration/apis/aiops/index.ts @@ -7,7 +7,7 @@ import { AIOPS_ENABLED } from '@kbn/aiops-plugin/common'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import type { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('AIOps', function () { diff --git a/x-pack/test/api_integration_basic/apis/aiops/index.ts b/x-pack/test/api_integration_basic/apis/aiops/index.ts index d3748f0afe2993..b1b42e6f3c46fc 100644 --- a/x-pack/test/api_integration_basic/apis/aiops/index.ts +++ b/x-pack/test/api_integration_basic/apis/aiops/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import type { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('aiops basic license', function () { diff --git a/x-pack/test/api_integration_basic/apis/aiops/permissions.ts b/x-pack/test/api_integration_basic/apis/aiops/permissions.ts index 25b8366be98ba0..0d79f610bcac07 100644 --- a/x-pack/test/api_integration_basic/apis/aiops/permissions.ts +++ b/x-pack/test/api_integration_basic/apis/aiops/permissions.ts @@ -12,7 +12,7 @@ import expect from '@kbn/expect'; import type { ApiExplainLogRateSpikes } from '@kbn/aiops-plugin/common/api'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import type { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); diff --git a/x-pack/test/functional/apps/aiops/config.ts b/x-pack/test/functional/apps/aiops/config.ts new file mode 100644 index 00000000000000..214d3712ecbf9f --- /dev/null +++ b/x-pack/test/functional/apps/aiops/config.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + junit: { + reportName: 'Chrome X-Pack UI Functional Tests - aiops', + }, + }; +} diff --git a/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts b/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts new file mode 100644 index 00000000000000..63a538db09ea20 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/explain_log_rate_spikes.ts @@ -0,0 +1,87 @@ +/* + * 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 type { FtrProviderContext } from '../../ftr_provider_context'; +import type { TestData } from './types'; +import { farequoteDataViewTestData } from './test_data'; + +export default function ({ getPageObject, getService }: FtrProviderContext) { + const headerPage = getPageObject('header'); + const esArchiver = getService('esArchiver'); + const aiops = getService('aiops'); + + // aiops / Explain Log Rate Spikes lives in the ML UI so we need some related services. + const ml = getService('ml'); + + function runTests(testData: TestData) { + it(`${testData.suiteTitle} loads the source data in explain log rate spikes`, async () => { + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the saved search selection page` + ); + await aiops.explainLogRateSpikes.navigateToIndexPatternSelection(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the explain log rate spikes page` + ); + await ml.jobSourceSelection.selectSourceForExplainLogRateSpikes( + testData.sourceIndexOrSavedSearch + ); + }); + + it(`${testData.suiteTitle} displays index details`, async () => { + await ml.testExecution.logTestStep(`${testData.suiteTitle} displays the time range step`); + await aiops.explainLogRateSpikes.assertTimeRangeSelectorSectionExists(); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} loads data for full time range`); + await aiops.explainLogRateSpikes.clickUseFullDataButton( + testData.expected.totalDocCountFormatted + ); + await headerPage.waitUntilLoadingHasFinished(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} displays elements in the doc count panel correctly` + ); + await aiops.explainLogRateSpikes.assertTotalDocCountHeaderExist(); + await aiops.explainLogRateSpikes.assertTotalDocCountChartExist(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} displays elements in the page correctly` + ); + + await aiops.explainLogRateSpikes.assertSearchPanelExist(); + + await ml.testExecution.logTestStep('displays empty prompt'); + await aiops.explainLogRateSpikes.assertNoWindowParametersEmptyPromptExist(); + }); + } + + describe('explain log rate spikes', function () { + this.tags(['aiops']); + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + + await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.setKibanaTimeZoneToUTC(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + }); + + describe('with farequote', function () { + // Run tests on full farequote index. + it(`${farequoteDataViewTestData.suiteTitle} loads the explain log rate spikes page`, async () => { + // Start navigation from the base of the ML app. + await ml.navigation.navigateToMl(); + }); + + runTests(farequoteDataViewTestData); + }); + }); +} diff --git a/x-pack/test/functional/apps/aiops/index.ts b/x-pack/test/functional/apps/aiops/index.ts new file mode 100644 index 00000000000000..88dea0b1d3e7e4 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/index.ts @@ -0,0 +1,38 @@ +/* + * 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 type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + + // aiops / Explain Log Rate Spikes lives in the ML UI so we need some related services. + const ml = getService('ml'); + + describe('aiops', function () { + this.tags(['skipFirefox', 'aiops']); + + before(async () => { + await ml.securityCommon.createMlRoles(); + await ml.securityCommon.createMlUsers(); + }); + + after(async () => { + // NOTE: Logout needs to happen before anything else to avoid flaky behavior + await ml.securityUI.logout(); + + await ml.securityCommon.cleanMlUsers(); + await ml.securityCommon.cleanMlRoles(); + + await esArchiver.unload('x-pack/test/functional/es_archives/ml/farequote'); + + await ml.testResources.resetKibanaTimeZone(); + }); + + loadTestFile(require.resolve('./explain_log_rate_spikes')); + }); +} diff --git a/x-pack/test/functional/apps/aiops/test_data.ts b/x-pack/test/functional/apps/aiops/test_data.ts new file mode 100644 index 00000000000000..8b9e332f867066 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/test_data.ts @@ -0,0 +1,17 @@ +/* + * 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 { TestData } from './types'; + +export const farequoteDataViewTestData: TestData = { + suiteTitle: 'farequote index pattern', + isSavedSearch: false, + sourceIndexOrSavedSearch: 'ft_farequote', + expected: { + totalDocCountFormatted: '86,274', + }, +}; diff --git a/x-pack/test/functional/apps/aiops/types.ts b/x-pack/test/functional/apps/aiops/types.ts new file mode 100644 index 00000000000000..2f58ef0ff754e8 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/types.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +export interface TestData { + suiteTitle: string; + isSavedSearch?: boolean; + sourceIndexOrSavedSearch: string; + rowsPerPage?: 10 | 25 | 50; + expected: { + totalDocCountFormatted: string; + }; +} diff --git a/x-pack/test/functional/services/aiops/explain_log_rate_spikes.ts b/x-pack/test/functional/services/aiops/explain_log_rate_spikes.ts new file mode 100644 index 00000000000000..41a205f43d66fb --- /dev/null +++ b/x-pack/test/functional/services/aiops/explain_log_rate_spikes.ts @@ -0,0 +1,64 @@ +/* + * 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 expect from '@kbn/expect'; + +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export function ExplainLogRateSpikesProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + + return { + async assertTimeRangeSelectorSectionExists() { + await testSubjects.existOrFail('aiopsTimeRangeSelectorSection'); + }, + + async assertTotalDocumentCount(expectedFormattedTotalDocCount: string) { + await retry.tryForTime(5000, async () => { + const docCount = await testSubjects.getVisibleText('aiopsTotalDocCount'); + expect(docCount).to.eql( + expectedFormattedTotalDocCount, + `Expected total document count to be '${expectedFormattedTotalDocCount}' (got '${docCount}')` + ); + }); + }, + + async clickUseFullDataButton(expectedFormattedTotalDocCount: string) { + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.clickWhenNotDisabled('aiopsExplainLogRatesSpikeButtonUseFullData'); + await testSubjects.clickWhenNotDisabled('superDatePickerApplyTimeButton'); + await this.assertTotalDocumentCount(expectedFormattedTotalDocCount); + }); + }, + + async assertTotalDocCountHeaderExist() { + await retry.tryForTime(5000, async () => { + await testSubjects.existOrFail(`aiopsTotalDocCountHeader`); + }); + }, + + async assertTotalDocCountChartExist() { + await retry.tryForTime(5000, async () => { + await testSubjects.existOrFail(`aiopsDocumentCountChart`); + }); + }, + + async assertSearchPanelExist() { + await testSubjects.existOrFail(`aiopsSearchPanel`); + }, + + async assertNoWindowParametersEmptyPromptExist() { + await testSubjects.existOrFail(`aiopsNoWindowParametersEmptyPrompt`); + }, + + async navigateToIndexPatternSelection() { + await testSubjects.click('mlMainTab explainLogRateSpikes'); + await testSubjects.existOrFail('mlPageSourceSelection'); + }, + }; +} diff --git a/x-pack/test/functional/services/aiops/index.ts b/x-pack/test/functional/services/aiops/index.ts new file mode 100644 index 00000000000000..e8a1b13cd6ad21 --- /dev/null +++ b/x-pack/test/functional/services/aiops/index.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 type { FtrProviderContext } from '../../ftr_provider_context'; + +import { ExplainLogRateSpikesProvider } from './explain_log_rate_spikes'; + +export function AiopsProvider(context: FtrProviderContext) { + const explainLogRateSpikes = ExplainLogRateSpikesProvider(context); + + return { + explainLogRateSpikes, + }; +} diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index 62e8ab1ac464da..7c09843efd9c16 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -70,6 +70,7 @@ import { SearchSessionsService } from './search_sessions'; import { ObservabilityProvider } from './observability'; import { CompareImagesProvider } from './compare_images'; import { CasesServiceProvider } from './cases'; +import { AiopsProvider } from './aiops'; // define the name and providers for services that should be // available to your tests. If you don't specify anything here @@ -130,4 +131,5 @@ export const services = { observability: ObservabilityProvider, compareImages: CompareImagesProvider, cases: CasesServiceProvider, + aiops: AiopsProvider, }; diff --git a/x-pack/test/functional/services/ml/job_source_selection.ts b/x-pack/test/functional/services/ml/job_source_selection.ts index e215f9b857435a..9fa51b01516a53 100644 --- a/x-pack/test/functional/services/ml/job_source_selection.ts +++ b/x-pack/test/functional/services/ml/job_source_selection.ts @@ -42,5 +42,9 @@ export function MachineLearningJobSourceSelectionProvider({ getService }: FtrPro async selectSourceForIndexBasedDataVisualizer(sourceName: string) { await this.selectSource(sourceName, 'dataVisualizerIndexPage'); }, + + async selectSourceForExplainLogRateSpikes(sourceName: string) { + await this.selectSource(sourceName, 'aiopsExplainLogRateSpikesPage'); + }, }; } From 00c64ab94c9b22596de63f99e53dab75fe551b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 11 Aug 2022 12:25:57 +0200 Subject: [PATCH 09/59] [DOCS] Adds AIOps section and explain log rate spikes docs (#138485) Co-authored-by: Lisa Cawley --- .../ml/images/ml-explain-log-rate-before.png | Bin 0 -> 93841 bytes docs/user/ml/images/ml-explain-log-rate.png | Bin 0 -> 129559 bytes docs/user/ml/index.asciidoc | 45 ++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 docs/user/ml/images/ml-explain-log-rate-before.png create mode 100644 docs/user/ml/images/ml-explain-log-rate.png diff --git a/docs/user/ml/images/ml-explain-log-rate-before.png b/docs/user/ml/images/ml-explain-log-rate-before.png new file mode 100644 index 0000000000000000000000000000000000000000..e154ddbeebebfd3059b31df84ee087ae9d40b537 GIT binary patch literal 93841 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 Q1o)GBEB~fQOdtIJ0XIye(EtDd literal 0 HcmV?d00001 diff --git a/docs/user/ml/images/ml-explain-log-rate.png b/docs/user/ml/images/ml-explain-log-rate.png new file mode 100644 index 0000000000000000000000000000000000000000..c814ec50d6774e81638e85e50fbcdfa8a39b9097 GIT binary patch literal 129559 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 B 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 literal 0 HcmV?d00001 diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index e66ca4ee197807..33ad1660c2abf7 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -98,3 +98,48 @@ image::user/ml/images/outliers.png[{oldetection-cap} results in {kib}] For more information about the {dfanalytics} feature, see {ml-docs}/ml-dfanalytics.html[{ml-cap} {dfanalytics}]. + +[[xpack-ml-aiops]] +== AIOps + +AIOps is a part of {ml-app} in {kib} which provides features that use advanced +statistical methods to help you interpret your data and its behavior. + +[discrete] +[[explain-log-rate-spikes]] +=== Explain log rate spikes + +preview::[] + +Explain log rate spikes is a feature that uses advanced statistical methods to +identify reasons for increases in log rates. It makes it easy to find and +investigate causes of unusual spikes by using the analysis workflow view. +Examine the histogram chart of the log rates for a given {data-source}, and find +the reason behind a particular change possibly in millions of log events across +multiple fields and values. + +You can find explain log rate spikes under **{ml-app}** > **AIOps** where you +can select the {data-source} or saved search that you want to analyze. + +[role="screenshot"] +image::user/ml/images/ml-explain-log-rate-before.png[Log event histogram chart] + +Select a spike in the log event histogram chart to start the analysis. It +identifies statistically significant field-value combinations that contribute to +the spike and displays them in a table. The table also shows an indicator of the +level of impact and a sparkline showing the shape of the impact in the chart. +Hovering over a row displays the impact on the histogram chart in more detail. +You can also pin a table row by clicking on it then move the cursor to the +histogram chart. It displays a tooltip with exact count values for the pinned +field which enables closer investigation. + +Brushes in the chart show the baseline time range and the deviation in the +analyzed data. You can move the brushes to redefine both the baseline and the +deviation and rerun the analysis with the modified values. + +[role="screenshot"] +image::user/ml/images/ml-explain-log-rate.png[Log rate spike explained] + + + + From a182b8e9be6b6cd2aa5699a82fe3d7d7714c2574 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 11 Aug 2022 12:31:49 +0200 Subject: [PATCH 10/59] Files plugin (#137421) * added files plugin * [Files] Create files saved object and blob storage (#131886) * initial version of file saved objects * initial version of file saved objects part ii * added .blob index and setup logic for the file service and the blob service * wip: need to add .blob access to kibana_system role * use multiple-isolated after speaking of oleg * added metadata field * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs' * updated file statuses per feedback * removed created_by and added "alt" text field and converted "name" to type "text" too * split content_type into mime and extension * use BlobStorage interface in adapters prop * minor fixes * handle multiple Kibanas at startup time * fix jest test * do not set up index at setup time * set importable exportable to false explicitly * remove use of non-existent function * added plugin ID, use type instead of interface to avoid specific interface issue and use typescript to check that properties map corresponds to type * remove storage_id for now * make the name snake case! * added fixmes Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> * [Files] Implement ES-based blob store (#132123) * minor clean up * remove unused import * added modified version of the content stream from reporting * remove plugin_id, replace with file_kind * remove unused commented out code and clean up imports * added jest.config.js * added FileChunkDocument interface and added the head_chunk_id for easier deletion of related file chunks * added an additional test case for writing with content stream * first implementation of ES blob storage * fix imports * get closer to a final version of the blobstore interface, use esClient.get rather than esClient.search since we are using IDs * added jest integration tests * add some comments * fix: eslint types issues * remove unused values * minor refactor for clarity * fix when saved objects are registered * remove unused variable * fix jest tests and make getMaxSize function sync * fix logger prefixes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> * [Files] File service CRUD functionality and audit logging (#132416) * big ol wipperooni, but got a lot of initial functionality written out * added some todos and fixed import * finish adding integration tests for file service! also added the partial update capability to file * added file service integration tests and finalized Files and InternalFileService APIs * added security plugin * big refactor for security audit logging: FileServiceFactory * type lint * update delete file integration test and remove done TODOs * move comment * docs, accessibility modifiers and updated some import ordering * fix comments * pass in index name to ES blob store * tidy up debug and error messages * [Files] Added more chunking Jest integration tests (#132530) * added more thorough integration tests of chunking * refactor chunksize to a value that is passed to the ES constructor, update a comment and update tests * [Files] Public API v1 (#132602) * created public API, everything except the file registry * ensure the custom meta types are working as expected * added index: false to content * Revert "added index: false to content" This reverts commit 74259f86638aefc24755874cbd6ac89e0170c192. * updated comment * update how ids are generated * also filter out deleted files * fix id generation * test file deletion after upload failure * [Files] File kinds registry v0.1 (#132700) * initial commit of file kind registry * add actual registry * updated attributes reduceer slightly * separate blob storage interface, make the blob storage type a unique const * added integration test for file kinds * update test after adding registry logic * partial attributes * [Files] Blob storage with attributes (#134057) * updated blob storage interface with attributes * added dynamic: false to the file chunk doc for ES blob store * update mocks * support attributes at the blob store level part i * actually test setting of attributes, also refactor app_extra_data to app_meta_data * remove unused import * some corrections to tests, also refresh after creating a blob that has attributes to enable search * remove unnecessary default * getBaseId -> getContentReferenceId and added a bunch of doc comments * refactored getting of attribute chunk id, encapsulate everything inside content stream * remove app_search_data * app_meta_data -> app_metadata * [Files] Added `Transform` to blob stores (#134846) * added max byte size stream transform * added stream transforms to files * rename MaxByteSize to MaxByteSizeTransform * try a cool cool ternary, yeah * minor refactor * address PR feedback * [Files] File kind HTTP APIs and tests (#134655) * first version of dynamically creating file kinds routes * added update, delete, download, list and find endpoints and some minor refactoring * added return statement and additional requirement for file kind ids to be URI safe * update comment * added API integration tests for the file kinds routes, a lot of refactoring; removed the upload endpoint service since this does not make since with proxies, fixed a bunch of issues in registering routes and the enhanced file kind router * move the method to the specific route file too * remove unused function * add download content type response header * remove unused import * download http method should be "get" not "delete" * actually pass through the mime type * slight refactor after changing the create file response * findFile => getById * remove trailing verbs * update copy * addressing pr feedback * added missing property * fix copy * added comment * regrouping imoprts * rename "find" route to "getById" * [File storage] Public-side Client (#135403) * refactor store name * wip: first version of restful-ish endpoint types captured in one place except for path * use the endpoint definition directly * added first iteration of files client based on shared types * slight refactor * added content type headers and removed unused type * slight refactor and expose server and public side types * finish refactor * updated files plugin ui limits * [Files] Public file sharing service (#135598) * add new public file saved object type * generate random token * file share service, first iteration * initial version of files share service work, we can create a file share * delete shares when a file is deleted * refactor to InternalFileSharingService because certain events need to be audited * further clean up and added a comment * finish refactor * update tests * refactor tractor * move integration tests folder * does not need to be async, also added some samples to doc comment * added comment * use SO object references instead of hacking it yourself, also added comments and moved some stuff around * refactor to internal file share service * fix type lint * valid_until as unix ts * commit simplify random string generator * fix type issues and update SO integration tests * woops, 51 not 55 * change label * minor refactor to file service (#135836) * remove attributes from blobstore layer and update IDs to be xxxxx.1 instead of 1.xxxxx (#136294) * [Files] Refactor File metadata (#136370) * refactor tractor keeps on rolling * fix type issues * [Files] Conform with new blob store specification (#136396) * refactor es mappings * move puid file * updated the content stream implementation to support identifying "last" chunk * updated the es blob store * updated es mappings * minor updates to the file object, but importantly, passing the file ID to the blob store so that files and blobs are connected * updated test assertion * rather use cuid because it uses cryptography to reduce the chance of collisions (#136658) * do not index bid field (#136707) * [Files] Find endpoint (#136529) * refactor http endpoint interface names * wip on find files route, need to create shared test harness and test utils * added toJSON helper * pass through the filter * fix refactor to "getById" on file service instead of find and move order of attributes * actually add the toJSON utility * added shared integration test setup code * added find route path to common * return if 400 is returned when trying to create blob storage index. This is an edge case that can be hit if creation happens at the same time * update the find algo to build a kuery expression string that we pass to SO service, note: we want to prevent query injection shenanigans so we JSON.stringify * updated the create endpoint to enforce mime type from file type, thank you * updated the create endpoint to enforce mime type from file type, thank you * updated some tests and actually register the find enpoint, also updated to use mimeType * added a few integration level tests for the new find endpoint * updated the new setup integration test harness for use in new find and old file kinds integration tests * use flattened type for "Meta" and "hash" fields on saved object so that we can store multiple values in an object and search * updated import with "type" annotation * added readme explaining patterns used for routes * fix file kind integration tests * remove unused endpoint * do not expose chunk size and compression for now * use nodeBuilder rather than manually building a kuery string * make query strings limited in length and refactor "Extension" to "extension" plus some other minor changes * reorg some lines * [Files] Use `application/cbor` to optimise file uploads and downloads (#136528) * move puid file * added cbor-x dependency * remove all references to "raw" from the test code * remove "encoding" parameter and refactor to use cbor encoding for blob chunks, in this way we do not encoding our payloads to UTF-8 or Base64 Kibana side, only decode * fixed content stream tests * require instead of import cbor-x for now * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * try disable eslint comment scoped * download also as cbor to buffer directly, also updated upload endpoint to report when content has already been uploaded * updated tests and handle some edge case when reading buffers * remove unused require and added a comment * moved lengthy comment to separate file Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> * [Files] Added metrics endpoint and functionality (#136725) * added service-level functionality for getting usage metrics * built the metrics endpoint * do not count size of deleted files * updated comment * added agg by status and extension * update test assertions * [Files] File errors (#136946) * added domain-specific errors * map file errors to http responses and clean up list endpoint * [Files] Public File share HTTP endpoints (#137172) * refactor where server and client routes are declared * added new endpoint types and refactor api/files/files/metrics|share to api/files/metrics|share * added some more comments, a new error type for the file share service and created the endpoint handler for creating file shares * added doc comments to the file kind interface * rename test utils folder to "test_utils" and added a basic test for creating a share * added test_util folder and updated share test * added new endpoint types, updated import to test utils, updated share name * added unshare endpoint * added share list endpoint and refactored share JSON with version that contains token and version without * actually register the list shares route * a bunch of refactoring for saved object type "id" rather than "token" for the object id, also added the public download endpoint * updated error behavior on download endpoint * fixed test * use unix timestamp in seconds * added file name param to public download endpoint and added shared fileName schema * remove unused file and added public download tests * share to shares * added get endopint and updated tests and test titles per feedback * added get endpoint * updated test and back to milliseconds on validUntil * updated name of params in route and update error message in response * return only known messages in the expected format * update test * use Readable.from * reintroduce crazy typecasting * added security audit log tests (#137253) * [Files] Generate download headers utility tests (#137203) * move common schema to common schema file and move THAT file to a shared location * update mime type behaviour * update integration tests * added a little something to the README * update cbor-x to latest * delete "require" of cbor-x * upgrade cbor-x * rename "public" to "public_facing" * remove old lint rule * added a bunch of docs * fix interface surface area * more doc comments * more more doc comments * more more more doc comments * more more more more doc comments * more more more more more more doc comments * Actually 50GiB Co-authored-by: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> * Remove unnecessary comment Co-authored-by: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> * hasContent -> isReady * only call the createIndexIfNotExists function once per instance * [Files] Create files client (#137879) * biig refactor to use FileClient in File and remove all metadata functionality from file service * update file service factory to work with metadata client after refactor * also rename file share updateable attrs interface * updated use of types in saved objects client * export function arg types * added the creation helper file and added an example file for using it * implement find for the es index client * moved the query builder logic to a shared place * rename file, add prefixes and embed es doc in "file" key in ES document * type exports * fix bad rebase * Minor changes and updates to types * fix another minor type issue * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * fix minor type issues and update "update" behavior to only apply updatable fields bru * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * actually be able to update status... also some other types cleanups * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> * remove TODO * update link to team * throw errors more consistently * createAuditLog -> writeAuditLog * more more more more more more more doc comments * more more more more more more more more doc comments * more more more more more more more more more doc comments * more more more more more more more more more more doc comments * more more more more more more more more more more more more doc comments * [Files] ES client tests (#138174) * move test utils and update expected metric size * remove cuid from "file" * update file client to set id using cuid and update types * moved test utils and wip of integration tests for file client * added es-index backed file client tests * adjust the upload endpoint to also return the file size * added size to response expect * fix some type issues * fix type issues * [Files] Register routes at setup time (#138392) * updated the fileKindRegistory to live behind a getter setter so that instantation can be taken care of in one place * refactor conditional endpoint registration and update tests to register file kind after setup * register routes at setup time * remove outdated README * fix import of non-existent function * register routes... * [Files] PR feedback 1 (#138417) * update comments and plugin description * filter lists and finds on non-deleted files * updated comment * added tests for larger files and files exactly divisible by chunk size * [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs' * do not use regexp * fix test assertion * update content stream tests * make fewer fields searchable * ok Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> * remove legacy comment Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Vadim Kibana <82822460+vadimkibana@users.noreply.github.com> --- .github/CODEOWNERS | 1 + docs/developer/plugin-list.asciidoc | 4 + package.json | 2 + packages/kbn-optimizer/limits.yml | 1 + .../migrations/type_registrations.test.ts | 2 + src/core/test_helpers/kbn_server.ts | 3 +- tsconfig.base.json | 2 + x-pack/plugins/files/.i18nrc.json | 7 + x-pack/plugins/files/README.md | 13 + x-pack/plugins/files/common/api_routes.ts | 209 +++++++ x-pack/plugins/files/common/constants.ts | 29 + x-pack/plugins/files/common/index.ts | 29 + x-pack/plugins/files/common/types.ts | 519 ++++++++++++++++++ x-pack/plugins/files/jest.config.js | 15 + .../plugins/files/jest.integration.config.js | 12 + x-pack/plugins/files/kibana.json | 14 + .../files/public/files_client/files_client.ts | 68 +++ .../files/public/files_client/index.ts | 8 + x-pack/plugins/files/public/index.ts | 14 + x-pack/plugins/files/public/plugin.ts | 45 ++ x-pack/plugins/files/public/types.ts | 84 +++ x-pack/plugins/files/server/audit_events.ts | 36 ++ .../blob_storage_service/adapters/README.md | 6 + .../es/content_stream/content_stream.test.ts | 334 +++++++++++ .../es/content_stream/content_stream.ts | 382 +++++++++++++ .../adapters/es/content_stream/index.ts | 20 + .../blob_storage_service/adapters/es/es.ts | 139 +++++ .../blob_storage_service/adapters/es/index.ts | 8 + .../adapters/es/integration_tests/es.test.ts | 162 ++++++ .../adapters/es/mappings.ts | 43 ++ .../blob_storage_service/adapters/index.ts | 8 + .../blob_storage_service.ts | 44 ++ .../server/blob_storage_service/index.ts | 10 + .../server/blob_storage_service/types.ts | 73 +++ x-pack/plugins/files/server/file/errors.ts | 20 + x-pack/plugins/files/server/file/file.test.ts | 85 +++ x-pack/plugins/files/server/file/file.ts | 267 +++++++++ .../server/file/file_attributes_reducer.ts | 72 +++ x-pack/plugins/files/server/file/index.ts | 14 + x-pack/plugins/files/server/file/to_json.ts | 36 ++ .../file_client/create_es_file_client.ts | 60 ++ .../files/server/file_client/file_client.ts | 191 +++++++ .../file_metadata_client/adapters/es_index.ts | 149 +++++ .../file_metadata_client/adapters/index.ts | 9 + .../adapters/query_filters.ts | 62 +++ .../adapters/saved_objects.ts | 160 ++++++ .../file_metadata_client.ts | 137 +++++ .../file_client/file_metadata_client/index.ts | 18 + .../plugins/files/server/file_client/index.ts | 22 + .../integration_tests/es_file_client.test.ts | 217 ++++++++ .../file_client/stream_transforms/index.ts | 8 + .../max_byte_size_transform/errors.ts | 13 + .../max_byte_size_transform/index.ts | 8 + .../max_byte_size_transform.test.ts | 40 ++ .../max_byte_size_transform.ts | 26 + .../files/server/file_kinds_registry/index.ts | 66 +++ .../files/server/file_service/errors.ts | 13 + .../server/file_service/file_action_types.ts | 118 ++++ .../files/server/file_service/file_service.ts | 108 ++++ .../file_service/file_service_factory.ts | 140 +++++ .../files/server/file_service/index.ts | 18 + .../file_service/internal_file_service.ts | 156 ++++++ .../files/server/file_share_service/errors.ts | 19 + .../generate_share_token.test.ts | 16 + .../generate_share_token.ts | 31 ++ .../files/server/file_share_service/index.ts | 17 + .../internal_file_share_service.ts | 233 ++++++++ .../files/server/file_share_service/types.ts | 43 ++ x-pack/plugins/files/server/index.ts | 48 ++ .../files/server/integration_tests/README.md | 10 + .../integration_tests/file_service.test.ts | 346 ++++++++++++ x-pack/plugins/files/server/plugin.ts | 87 +++ .../plugins/files/server/routes/api_routes.ts | 37 ++ .../files/server/routes/common.test.ts | 48 ++ x-pack/plugins/files/server/routes/common.ts | 27 + .../files/server/routes/common_schemas.ts | 45 ++ .../files/server/routes/file_kind/create.ts | 62 +++ .../files/server/routes/file_kind/delete.ts | 67 +++ .../files/server/routes/file_kind/download.ts | 72 +++ .../server/routes/file_kind/enhance_router.ts | 51 ++ .../server/routes/file_kind/get_by_id.ts | 53 ++ .../files/server/routes/file_kind/helpers.ts | 38 ++ .../files/server/routes/file_kind/index.ts | 44 ++ .../integration_tests/file_kind_http.test.ts | 229 ++++++++ .../files/server/routes/file_kind/list.ts | 56 ++ .../server/routes/file_kind/share/get.ts | 64 +++ .../server/routes/file_kind/share/list.ts | 61 ++ .../server/routes/file_kind/share/share.ts | 95 ++++ .../server/routes/file_kind/share/unshare.ts | 67 +++ .../files/server/routes/file_kind/types.ts | 22 + .../files/server/routes/file_kind/update.ts | 71 +++ .../files/server/routes/file_kind/upload.ts | 78 +++ x-pack/plugins/files/server/routes/find.ts | 81 +++ x-pack/plugins/files/server/routes/index.ts | 18 + .../routes/integration_tests/routes.test.ts | 245 +++++++++ x-pack/plugins/files/server/routes/metrics.ts | 32 ++ .../server/routes/public_facing/download.ts | 86 +++ x-pack/plugins/files/server/routes/types.ts | 38 ++ .../files/server/saved_objects/file.ts | 58 ++ .../files/server/saved_objects/file_share.ts | 44 ++ .../files/server/saved_objects/index.ts | 9 + .../plugins/files/server/test_utils/index.ts | 9 + .../setup_integration_environment.ts | 131 +++++ x-pack/plugins/files/server/types.ts | 36 ++ x-pack/plugins/files/tsconfig.json | 14 + yarn.lock | 61 ++ 106 files changed, 7577 insertions(+), 1 deletion(-) create mode 100755 x-pack/plugins/files/.i18nrc.json create mode 100755 x-pack/plugins/files/README.md create mode 100644 x-pack/plugins/files/common/api_routes.ts create mode 100644 x-pack/plugins/files/common/constants.ts create mode 100755 x-pack/plugins/files/common/index.ts create mode 100644 x-pack/plugins/files/common/types.ts create mode 100644 x-pack/plugins/files/jest.config.js create mode 100644 x-pack/plugins/files/jest.integration.config.js create mode 100755 x-pack/plugins/files/kibana.json create mode 100644 x-pack/plugins/files/public/files_client/files_client.ts create mode 100644 x-pack/plugins/files/public/files_client/index.ts create mode 100644 x-pack/plugins/files/public/index.ts create mode 100644 x-pack/plugins/files/public/plugin.ts create mode 100644 x-pack/plugins/files/public/types.ts create mode 100644 x-pack/plugins/files/server/audit_events.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/README.md create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/index.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/es.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/index.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/es/mappings.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/adapters/index.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/blob_storage_service.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/index.ts create mode 100644 x-pack/plugins/files/server/blob_storage_service/types.ts create mode 100644 x-pack/plugins/files/server/file/errors.ts create mode 100644 x-pack/plugins/files/server/file/file.test.ts create mode 100644 x-pack/plugins/files/server/file/file.ts create mode 100644 x-pack/plugins/files/server/file/file_attributes_reducer.ts create mode 100644 x-pack/plugins/files/server/file/index.ts create mode 100644 x-pack/plugins/files/server/file/to_json.ts create mode 100644 x-pack/plugins/files/server/file_client/create_es_file_client.ts create mode 100644 x-pack/plugins/files/server/file_client/file_client.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/adapters/es_index.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/adapters/index.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts create mode 100644 x-pack/plugins/files/server/file_client/file_metadata_client/index.ts create mode 100644 x-pack/plugins/files/server/file_client/index.ts create mode 100644 x-pack/plugins/files/server/file_client/integration_tests/es_file_client.test.ts create mode 100644 x-pack/plugins/files/server/file_client/stream_transforms/index.ts create mode 100644 x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/errors.ts create mode 100644 x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/index.ts create mode 100644 x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.test.ts create mode 100644 x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.ts create mode 100644 x-pack/plugins/files/server/file_kinds_registry/index.ts create mode 100644 x-pack/plugins/files/server/file_service/errors.ts create mode 100644 x-pack/plugins/files/server/file_service/file_action_types.ts create mode 100644 x-pack/plugins/files/server/file_service/file_service.ts create mode 100644 x-pack/plugins/files/server/file_service/file_service_factory.ts create mode 100644 x-pack/plugins/files/server/file_service/index.ts create mode 100644 x-pack/plugins/files/server/file_service/internal_file_service.ts create mode 100644 x-pack/plugins/files/server/file_share_service/errors.ts create mode 100644 x-pack/plugins/files/server/file_share_service/generate_share_token.test.ts create mode 100644 x-pack/plugins/files/server/file_share_service/generate_share_token.ts create mode 100644 x-pack/plugins/files/server/file_share_service/index.ts create mode 100644 x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts create mode 100644 x-pack/plugins/files/server/file_share_service/types.ts create mode 100755 x-pack/plugins/files/server/index.ts create mode 100644 x-pack/plugins/files/server/integration_tests/README.md create mode 100644 x-pack/plugins/files/server/integration_tests/file_service.test.ts create mode 100755 x-pack/plugins/files/server/plugin.ts create mode 100644 x-pack/plugins/files/server/routes/api_routes.ts create mode 100644 x-pack/plugins/files/server/routes/common.test.ts create mode 100644 x-pack/plugins/files/server/routes/common.ts create mode 100644 x-pack/plugins/files/server/routes/common_schemas.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/create.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/delete.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/download.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/enhance_router.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/get_by_id.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/helpers.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/index.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/list.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/share/get.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/share/list.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/share/share.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/share/unshare.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/types.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/update.ts create mode 100644 x-pack/plugins/files/server/routes/file_kind/upload.ts create mode 100644 x-pack/plugins/files/server/routes/find.ts create mode 100644 x-pack/plugins/files/server/routes/index.ts create mode 100644 x-pack/plugins/files/server/routes/integration_tests/routes.test.ts create mode 100644 x-pack/plugins/files/server/routes/metrics.ts create mode 100644 x-pack/plugins/files/server/routes/public_facing/download.ts create mode 100644 x-pack/plugins/files/server/routes/types.ts create mode 100644 x-pack/plugins/files/server/saved_objects/file.ts create mode 100644 x-pack/plugins/files/server/saved_objects/file_share.ts create mode 100644 x-pack/plugins/files/server/saved_objects/index.ts create mode 100644 x-pack/plugins/files/server/test_utils/index.ts create mode 100644 x-pack/plugins/files/server/test_utils/setup_integration_environment.ts create mode 100644 x-pack/plugins/files/server/types.ts create mode 100644 x-pack/plugins/files/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c51571ebaece68..19d2f1cdb27ef1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -85,6 +85,7 @@ /x-pack/plugins/runtime_fields @elastic/kibana-app-services /x-pack/test/search_sessions_integration/ @elastic/kibana-app-services /src/plugins/dashboard/public/application/embeddable/viewport/print_media @elastic/kibana-app-services +x-pack/plugins/files @elastic/kibana-app-services ### Observability Plugins diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 67626e0580390d..10bd6fbba96ce6 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -455,6 +455,10 @@ activities. |The features plugin enhance Kibana with a per-feature privilege system. +|{kib-repo}blob/{branch}/x-pack/plugins/files/README.md[files] +|File upload, download, sharing, and serving over HTTP implementation in Kibana. + + |{kib-repo}blob/{branch}/x-pack/plugins/file_upload[fileUpload] |WARNING: Missing README. diff --git a/package.json b/package.json index 90bd299ba581a8..e67bcca74beb76 100644 --- a/package.json +++ b/package.json @@ -371,6 +371,7 @@ "bitmap-sdf": "^1.0.3", "brace": "0.11.1", "canvg": "^3.0.9", + "cbor-x": "^1.3.3", "chalk": "^4.1.0", "cheerio": "^1.0.0-rc.10", "chroma-js": "^1.4.1", @@ -383,6 +384,7 @@ "copy-to-clipboard": "^3.0.8", "core-js": "^3.23.5", "cronstrue": "^1.51.0", + "cuid": "^2.1.8", "cytoscape": "^3.10.0", "cytoscape-dagre": "^2.2.2", "d3": "3.5.17", diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 955ec123c16264..c12c3081a737e6 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -133,3 +133,4 @@ pageLoadAssetSize: kibanaUsageCollection: 16463 kubernetesSecurity: 77234 threatIntelligence: 29195 + files: 22673 diff --git a/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts b/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts index f25868cc8dd3f1..b71529d2ff1a91 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts @@ -49,6 +49,8 @@ const previouslyRegisteredTypes = [ 'event_loop_delays_daily', 'exception-list', 'exception-list-agnostic', + 'file', + 'fileShare', 'file-upload-telemetry', 'file-upload-usage-collection-telemetry', 'fleet-agent-actions', diff --git a/src/core/test_helpers/kbn_server.ts b/src/core/test_helpers/kbn_server.ts index 022d60acbed9b5..faa45c52d84b8c 100644 --- a/src/core/test_helpers/kbn_server.ts +++ b/src/core/test_helpers/kbn_server.ts @@ -24,7 +24,7 @@ import { CliArgs, Env } from '@kbn/config'; import { InternalCoreSetup, InternalCoreStart } from '../server/internal_types'; import { Root } from '../server/root'; -export type HttpMethod = 'delete' | 'get' | 'head' | 'post' | 'put'; +export type HttpMethod = 'delete' | 'get' | 'head' | 'post' | 'put' | 'patch'; const DEFAULTS_SETTINGS = { server: { @@ -157,6 +157,7 @@ export const request: Record< head: (root, path) => getSupertest(root, 'head', path), post: (root, path) => getSupertest(root, 'post', path), put: (root, path) => getSupertest(root, 'put', path), + patch: (root, path) => getSupertest(root, 'patch', path), }; export interface TestElasticsearchUtils { diff --git a/tsconfig.base.json b/tsconfig.base.json index c3a37ced8434e4..04afc7e8bb049d 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -329,6 +329,8 @@ "@kbn/features-plugin/*": ["x-pack/plugins/features/*"], "@kbn/file-upload-plugin": ["x-pack/plugins/file_upload"], "@kbn/file-upload-plugin/*": ["x-pack/plugins/file_upload/*"], + "@kbn/files-plugin": ["x-pack/plugins/files"], + "@kbn/files-plugin/*": ["x-pack/plugins/files/*"], "@kbn/fleet-plugin": ["x-pack/plugins/fleet"], "@kbn/fleet-plugin/*": ["x-pack/plugins/fleet/*"], "@kbn/global-search-bar-plugin": ["x-pack/plugins/global_search_bar"], diff --git a/x-pack/plugins/files/.i18nrc.json b/x-pack/plugins/files/.i18nrc.json new file mode 100755 index 00000000000000..863f776e2a64ec --- /dev/null +++ b/x-pack/plugins/files/.i18nrc.json @@ -0,0 +1,7 @@ +{ + "prefix": "files", + "paths": { + "files": "." + }, + "translations": ["translations/ja-JP.json"] +} diff --git a/x-pack/plugins/files/README.md b/x-pack/plugins/files/README.md new file mode 100755 index 00000000000000..baaea2ecb44cd4 --- /dev/null +++ b/x-pack/plugins/files/README.md @@ -0,0 +1,13 @@ +# files + +File upload, download, sharing, and serving over HTTP implementation in Kibana. + +## Status + +The files plugin is currently still under development. If you want to use files please reach out to the (App Services team)[https://github.com/orgs/elastic/teams/kibana-app-services] and let's talk about your use case and share our current roadmap. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/x-pack/plugins/files/common/api_routes.ts b/x-pack/plugins/files/common/api_routes.ts new file mode 100644 index 00000000000000..f3647edaf83f0d --- /dev/null +++ b/x-pack/plugins/files/common/api_routes.ts @@ -0,0 +1,209 @@ +/* + * 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 { PLUGIN_ID } from './constants'; +import type { + FileJSON, + Pagination, + FilesMetrics, + FileShareJSON, + FileShareJSONWithToken, +} from './types'; + +export const API_BASE_PATH = `/api/${PLUGIN_ID}`; + +export const FILES_API_BASE_PATH = `${API_BASE_PATH}/files`; + +export const FILES_SHARE_API_BASE_PATH = `${API_BASE_PATH}/shares`; + +export const FILES_PUBLIC_API_BASE_PATH = `${API_BASE_PATH}/public`; + +/** + * Abstract type definition for API route inputs and outputs. + * + * These definitions should be shared between the public and server + * as the single source of truth. + */ +export interface HttpApiInterfaceEntryDefinition< + P = unknown, + Q = unknown, + B = unknown, + R = unknown +> { + inputs: { + params: P; + query: Q; + body: B; + }; + output: R; +} + +export type CreateFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + unknown, + unknown, + { + name: string; + alt?: string; + meta?: Record; + mimeType?: string; + }, + { file: FileJSON } +>; + +export type DeleteFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + id: string; + }, + unknown, + unknown, + { ok: true } +>; + +export type DownloadFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + id: string; + fileName?: string; + }, + unknown, + unknown, + any +>; + +export type GetByIdFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + id: string; + }, + unknown, + unknown, + { file: FileJSON } +>; + +export type ListFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + unknown, + Pagination, + unknown, + { files: FileJSON[] } +>; + +export type UpdateFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + { id: string }, + unknown, + { name?: string; alt?: string; meta?: Record }, + { file: FileJSON } +>; + +export type UploadFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< + { id: string }, + unknown, + any, + { + ok: true; + size: number; + } +>; + +export type FindFilesHttpEndpoint = HttpApiInterfaceEntryDefinition< + unknown, + Pagination, + { + /** + * Filter for set of file-kinds + */ + kind?: string[]; + + /** + * Filter for match on names + */ + name?: string[]; + + /** + * Filter for set of meta attributes matching this object + */ + meta?: {}; + + /** + * Filter for match on extensions + */ + extension?: string[]; + + /** + * Filter for match on extensions + */ + status?: string[]; + }, + { files: FileJSON[] } +>; + +export type FilesMetricsHttpEndpoint = HttpApiInterfaceEntryDefinition< + unknown, + unknown, + unknown, + FilesMetrics +>; + +export type FileShareHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + fileId: string; + }, + unknown, + { + /** + * Unix timestamp of when the share will expire. + */ + validUntil?: number; + /** + * Optional name to uniquely identify this share instance. + */ + name?: string; + }, + FileShareJSONWithToken +>; + +export type FileUnshareHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + /** + * Share token id + */ + id: string; + }, + unknown, + unknown, + { + ok: true; + } +>; + +export type FileGetShareHttpEndpoint = HttpApiInterfaceEntryDefinition< + { + /** + * ID of the share object + */ + id: string; + }, + unknown, + unknown, + { + share: FileShareJSON; + } +>; + +export type FileListSharesHttpEndpoint = HttpApiInterfaceEntryDefinition< + unknown, + Pagination & { forFileId?: string }, + unknown, + { + shares: FileShareJSON[]; + } +>; + +export type FilePublicDownloadHttpEndpoint = HttpApiInterfaceEntryDefinition< + { fileName?: string }, + { token: string }, + unknown, + // Should be a readable stream + any +>; diff --git a/x-pack/plugins/files/common/constants.ts b/x-pack/plugins/files/common/constants.ts new file mode 100644 index 00000000000000..be0bfa3ca80c4e --- /dev/null +++ b/x-pack/plugins/files/common/constants.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/** + * The files plugin ID + */ +export const PLUGIN_ID = 'files' as const; +/** + * The files plugin name + */ +export const PLUGIN_NAME = 'files' as const; + +/** + * Unique type name of the file saved object + */ +export const FILE_SO_TYPE = 'file'; +/** + * Unique type name of the public file saved object + */ +export const FILE_SHARE_SO_TYPE = 'fileShare'; + +/** + * The name of the fixed size ES-backed blob store + */ +export const ES_FIXED_SIZE_INDEX_BLOB_STORE = 'esFixedSizeIndex' as const; diff --git a/x-pack/plugins/files/common/index.ts b/x-pack/plugins/files/common/index.ts new file mode 100755 index 00000000000000..8a97030efff6f3 --- /dev/null +++ b/x-pack/plugins/files/common/index.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +export { FILE_SO_TYPE, PLUGIN_ID, PLUGIN_NAME, ES_FIXED_SIZE_INDEX_BLOB_STORE } from './constants'; + +export type { + File, + FileKind, + FileJSON, + FileShare, + FileStatus, + Pagination, + FileMetadata, + FilesMetrics, + FileShareJSON, + FileCompression, + FileSavedObject, + BaseFileMetadata, + FileShareOptions, + FileUnshareOptions, + BlobStorageSettings, + UpdatableFileMetadata, + FileShareJSONWithToken, + UpdatableFileShareMetadata, +} from './types'; diff --git a/x-pack/plugins/files/common/types.ts b/x-pack/plugins/files/common/types.ts new file mode 100644 index 00000000000000..2fef7ab3f17c4c --- /dev/null +++ b/x-pack/plugins/files/common/types.ts @@ -0,0 +1,519 @@ +/* + * 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 type { SavedObject } from '@kbn/core/server'; +import type { Readable } from 'stream'; +import type { ES_FIXED_SIZE_INDEX_BLOB_STORE } from './constants'; + +/** + * Values for paginating through results. + */ +export interface Pagination { + /** + * Page of results. + */ + page?: number; + /** + * Number of results per page. + */ + perPage?: number; +} + +/** + * Status of a file. + * + * AWAITING_UPLOAD - A file object has been created but does not have any contents. + * UPLOADING - File contents are being uploaded. + * READY - File contents have been uploaded and are ready for to be downloaded. + * UPLOAD_ERROR - An attempt was made to upload file contents but failed. + * DELETED - The file contents have been or are being deleted. + */ +export type FileStatus = 'AWAITING_UPLOAD' | 'UPLOADING' | 'READY' | 'UPLOAD_ERROR' | 'DELETED'; + +/** + * Supported file compression algorithms + */ +export type FileCompression = 'br' | 'gzip' | 'deflate' | 'none'; + +/** + * File metadata fields are defined per the ECS specification: + * + * https://www.elastic.co/guide/en/ecs/current/ecs-file.html + * + * Custom fields are named according to the custom field convention: "CustomFieldName". + */ +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type BaseFileMetadata = { + /** + * Name of the file + * + * @note This field is recommended since it will provide a better UX + */ + name?: string; + + /** + * MIME type of the file contents + */ + mime_type?: string; + + /** + * ISO string representing the file creation date + */ + created?: string; + + /** + * Size of the file + */ + size?: number; + + /** + * Hash of the file's contents + */ + hash?: { + /** + * UTF-8 string representing MD5 hash + */ + md5?: string; + /** + * UTF-8 string representing sha1 hash + */ + sha1?: string; + /** + * UTF-8 string representing sha256 hash + */ + sha256?: string; + /** + * UTF-8 string representing sha384 hash + */ + sha384?: string; + /** + * UTF-8 string representing sha512 hash + */ + sha512?: string; + /** + * UTF-8 string representing shadeep hash + */ + ssdeep?: string; + /** + * UTF-8 string representing tlsh hash + */ + tlsh?: string; + [hashName: string]: string | undefined; + }; + + /** + * The file extension, for example "jpg", "png", "svg" and so forth + */ + extension?: string; + + /** + * Alternate text that can be used used to describe the contents of the file + * in human-friendly language + */ + Alt?: string; + + /** + * ISO string representing when the file was last updated + */ + Updated?: string; + + /** + * The file's current status + */ + Status?: FileStatus; + + /** + * The maximum number of bytes per file chunk + */ + ChunkSize?: number; + + /** + * Compression algorithm used to transform chunks before they were stored. + */ + Compression?: FileCompression; +}; + +/** + * Extra metadata on a file object specific to Kibana implementation. + */ +export type FileMetadata = Required< + Pick +> & + BaseFileMetadata & { + /** + * Unique identifier of the kind of file. Kibana applications can register + * these at runtime. + */ + FileKind: string; + + /** + * User-defined metadata + */ + Meta?: Meta; + }; + +/** + * Attributes of a file that represent a serialised version of the file. + */ +export interface FileJSON { + /** + * Unique file ID. + */ + id: string; + /** + * ISO string of when this file was created + */ + created: FileMetadata['created']; + /** + * ISO string of when the file was updated + */ + updated: FileMetadata['Updated']; + /** + * File name. + * + * @note Does not have to be unique. + */ + name: FileMetadata['name']; + /** + * MIME type of the file's contents. + */ + mimeType: FileMetadata['mime_type']; + /** + * The size, in bytes, of the file content. + */ + size: FileMetadata['size']; + /** + * The file extension (dot suffix). + * + * @note this value can be derived from MIME type but is stored for search + * convenience. + */ + extension: FileMetadata['extension']; + + /** + * A consumer defined set of attributes. + * + * Consumers of the file service can add their own tags and identifiers to + * a file using the "meta" object. + */ + meta: FileMetadata['Meta']; + /** + * Use this text to describe the file contents for display and accessibility. + */ + alt: FileMetadata['Alt']; + /** + * A unique kind that governs various aspects of the file. A consumer of the + * files service must register a file kind and link their files to a specific + * kind. + * + * @note This enables stricter access controls to CRUD and other functionality + * exposed by the files service. + */ + fileKind: FileMetadata['FileKind']; + /** + * The current status of the file. + * + * See {@link FileStatus} for more details. + */ + status: FileMetadata['Status']; +} + +/** + * An {@link SavedObject} containing a file object (i.e., metadata only). + */ +export type FileSavedObject = SavedObject>; + +/** + * The set of file metadata that can be updated. + */ +export type UpdatableFileMetadata = Pick, 'meta' | 'alt' | 'name'>; + +/** + * Data stored with a file share object + */ +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type FileShare = { + /** + * ISO timestamp of when the file share was created. + */ + created: string; + + /** + * Secret token used to access the associated file. + */ + token: string; + + /** + * Human friendly name for this share token. + */ + name?: string; + + /** + * The unix timestamp (in milliseconds) this file share will expire. + * + * TODO: in future we could add a special value like "forever", but this should + * not be the default. + */ + valid_until: number; +}; + +/** + * Attributes of a file that represent a serialised version of the file. + */ +export interface FileShareJSON { + /** + * Unique ID share instance + */ + id: string; + /** + * ISO timestamp the share was created + */ + created: FileShare['created']; + /** + * Unix timestamp (in milliseconds) of when this share expires + */ + validUntil: FileShare['valid_until']; + /** + * A user-friendly name for the file share + */ + name?: FileShare['name']; + /** + * The ID of the file this share is linked to + */ + fileId: string; +} + +/** + * A version of the file share with a token included. + * + * @note This should only be shown when the file share is first created + */ +export type FileShareJSONWithToken = FileShareJSON & { + /** + * Secret token that can be used to access files + */ + token: string; +}; + +/** + * Set of attributes that can be updated in a file share. + */ +export type UpdatableFileShareMetadata = Pick; + +/** + * Arguments to pass to share a file + */ +export interface FileShareOptions { + /** + * Optional name for the file share, should be human-friendly. + */ + name?: string; + /** + * Unix timestamp (in milliseconds) when the file share will expire. + * + * @note default is 30 days + */ + validUntil?: number; +} +/** + * Arguments for unsharing a file + */ +export interface FileUnshareOptions { + /** + * Specify the share instance to remove + */ + shareId: string; +} + +/** + * A class with set of properties and behaviors of the "smart" file object and adds + * behaviours for interacting with files on top of the pure data. + */ +export interface File extends FileJSON { + /** + * Update a file object's metadatathat can be updated. + * + * @param attr - The of attributes to update. + */ + update(attr: Partial>): Promise>; + + /** + * Stream file content to storage. + * + * @param content - The content to stream to storage. + */ + uploadContent(content: Readable): Promise; + + /** + * Stream file content from storage. + */ + downloadContent(): Promise; + + /** + * Delete a file. + * + * @note This will delete the file metadata, contents and any other objects + * related to the file owned by files. + */ + delete(): Promise; + + /** + * Generate a secure token that can be used to access a file's content. + * + * @note This makes a file available for public download. Any agent with the + * token will bypass normal authz and authn checks. + * + * @param opts - Share file options. + */ + share(opts?: FileShareOptions): Promise; + + /** + * List all current {@link FileShareJSON} objects that have been created for + * a file. + */ + listShares(): Promise; + + /** + * Remove a {@link FileShareJSON} object therefore ceasing to share a file's + * content. + * + * @param opts - Unshare file options + */ + unshare(opts: FileUnshareOptions): Promise; + + /** + * Get a JSON representation of the file. Convenient for serialisation. + */ + toJSON(): FileJSON; +} + +/** + * Defines all the settings for supported blob stores. + * + * Key names map to unique blob store implementations and so must not be changed + * without a migration + */ +export interface BlobStorageSettings { + /** + * Single index that supports up to 50GB of blobs + */ + [ES_FIXED_SIZE_INDEX_BLOB_STORE]?: { + index: string; + }; + // Other blob store settings will go here once available +} + +interface HttpEndpointDefinition { + /** + * Specify the tags for this endpoint. + * + * @example + * // This will enable access control to this endpoint for users that can access "myApp" only. + * { tags: ['access:myApp'] } + * + */ + tags: string[]; +} + +/** + * A descriptor of meta values associated with a set or "kind" of files. + * + * @note In order to use the file service consumers must register a {@link FileKind} + * in the {@link FileKindsRegistry}. + */ +export interface FileKind { + /** + * Unique file kind ID + */ + id: string; + /** + * Maximum size, in bytes, a file of this kind can be. + */ + maxSizeBytes?: number; + + /** + * The MIME type of the file content. + * + * @default accept all mime types + */ + allowedMimeTypes?: string[]; + + /** + * Blob store specific settings that enable configuration of storage + * details. + */ + blobStoreSettings?: BlobStorageSettings; + + /** + * Optionally specify which HTTP routes to create for the file kind + */ + http: { + /** + * Enable creating this file type + */ + create?: HttpEndpointDefinition; + /** + * Enable the file metadata to updated + */ + update?: HttpEndpointDefinition; + /** + * Enable the file to be deleted (metadata and contents) + */ + delete?: HttpEndpointDefinition; + /** + * Enable file to be retrieved by ID. + */ + getById?: HttpEndpointDefinition; + /** + * Enable file to be listed + */ + list?: HttpEndpointDefinition; + /** + * Enable the file to be downloaded + */ + download?: HttpEndpointDefinition; + /** + * Enable the file to be shared publicly + */ + share?: HttpEndpointDefinition; + }; +} + +/** + * A collection of generally useful metrics about files. + */ +export interface FilesMetrics { + /** + * Metrics about all storage media. + */ + storage: { + /** + * The ES fixed size blob store. + */ + [ES_FIXED_SIZE_INDEX_BLOB_STORE]: { + /** + * The total size in bytes that can be used in this storage medium + */ + capacity: number; + /** + * Bytes currently used + */ + used: number; + /** + * Bytes currently available + */ + available: number; + }; + }; + /** + * A count of all files grouped by status + */ + countByStatus: Record; + /** + * A count of all files grouped by extension + */ + countByExtension: Record; +} diff --git a/x-pack/plugins/files/jest.config.js b/x-pack/plugins/files/jest.config.js new file mode 100644 index 00000000000000..ade30bacab1fab --- /dev/null +++ b/x-pack/plugins/files/jest.config.js @@ -0,0 +1,15 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/x-pack/plugins/files'], + coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/files', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/x-pack/plugins/files/{common,public,server}/**/*.{js,ts,tsx}'], +}; diff --git a/x-pack/plugins/files/jest.integration.config.js b/x-pack/plugins/files/jest.integration.config.js new file mode 100644 index 00000000000000..fbcfd8ed04b679 --- /dev/null +++ b/x-pack/plugins/files/jest.integration.config.js @@ -0,0 +1,12 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test/jest_integration', + rootDir: '../../..', + roots: ['/x-pack/plugins/files'], +}; diff --git a/x-pack/plugins/files/kibana.json b/x-pack/plugins/files/kibana.json new file mode 100755 index 00000000000000..73571304b194a9 --- /dev/null +++ b/x-pack/plugins/files/kibana.json @@ -0,0 +1,14 @@ +{ + "id": "files", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "@elastic/kibana-app-services", + "githubTeam": "team:AppServicesUx" + }, + "description": "File upload, download, sharing, and serving over HTTP implementation in Kibana.", + "server": true, + "ui": true, + "requiredPlugins": [], + "optionalPlugins": ["security"] +} diff --git a/x-pack/plugins/files/public/files_client/files_client.ts b/x-pack/plugins/files/public/files_client/files_client.ts new file mode 100644 index 00000000000000..ffa8e815368f00 --- /dev/null +++ b/x-pack/plugins/files/public/files_client/files_client.ts @@ -0,0 +1,68 @@ +/* + * 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 * as qs from 'query-string'; +import type { HttpStart } from '@kbn/core/public'; +import type { FilesClient } from '../types'; +import { FILES_API_BASE_PATH } from '../../common/api_routes'; + +const apiRoutes = { + getCreateFileRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}`, + getUploadRoute: (fileKind: string, id: string) => `${FILES_API_BASE_PATH}/${fileKind}/${id}/blob`, + getDownloadRoute: (fileKind: string, id: string, fileName?: string) => + `${FILES_API_BASE_PATH}/${fileKind}/${id}/blob/${fileName ? fileName : ''}`, + getUpdateRoute: (fileKind: string, id: string) => `${FILES_API_BASE_PATH}/${fileKind}/${id}`, + getDeleteRoute: (fileKind: string, id: string) => `${FILES_API_BASE_PATH}/${fileKind}/${id}`, + getListRoute: (fileKind: string, page?: number, perPage?: number) => { + const qParams = qs.stringify({ page, perPage }); + return `${FILES_API_BASE_PATH}/${fileKind}/list${qParams ? `?${qParams}` : ''}`; + }, + getByIdRoute: (fileKind: string, id: string) => `${FILES_API_BASE_PATH}/${fileKind}/${id}`, +}; + +interface Args { + fileKind: string; + http: HttpStart; +} + +export const createFilesClient = ({ http, fileKind }: Args): FilesClient => { + return { + create(args) { + return http.post(apiRoutes.getCreateFileRoute(fileKind), { + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(args), + }); + }, + delete(args) { + return http.delete(apiRoutes.getDeleteRoute(fileKind, args.id)); + }, + download(args) { + return http.get(apiRoutes.getDownloadRoute(fileKind, args.id, args.fileName)); + }, + getById(args) { + return http.get(apiRoutes.getByIdRoute(fileKind, args.id)); + }, + list(args) { + return http.get(apiRoutes.getListRoute(fileKind, args.page, args.perPage)); + }, + update({ id, ...body }) { + return http.patch(apiRoutes.getUpdateRoute(fileKind, id), { + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(body), + }); + }, + upload(args) { + return http.put(apiRoutes.getUploadRoute(fileKind, args.id), { + body: args.body, + }); + }, + }; +}; diff --git a/x-pack/plugins/files/public/files_client/index.ts b/x-pack/plugins/files/public/files_client/index.ts new file mode 100644 index 00000000000000..60f3022e825dfd --- /dev/null +++ b/x-pack/plugins/files/public/files_client/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { createFilesClient } from './files_client'; diff --git a/x-pack/plugins/files/public/index.ts b/x-pack/plugins/files/public/index.ts new file mode 100644 index 00000000000000..4b707aaa3b6a2a --- /dev/null +++ b/x-pack/plugins/files/public/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { FilesPlugin } from './plugin'; + +export type { FilesClient, FilesClientFactory } from './types'; + +export function plugin() { + return new FilesPlugin(); +} diff --git a/x-pack/plugins/files/public/plugin.ts b/x-pack/plugins/files/public/plugin.ts new file mode 100644 index 00000000000000..92358d067d36ad --- /dev/null +++ b/x-pack/plugins/files/public/plugin.ts @@ -0,0 +1,45 @@ +/* + * 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 type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { FilesClientFactory } from './types'; +import { createFilesClient } from './files_client'; + +/** + * Public setup-phase contract + */ +export interface FilesSetup { + /** + * A factory for creating an {@link FilesClient} instance. This requires a + * registered {@link FileKind}. + */ + filesClientFactory: FilesClientFactory; +} + +export type FilesStart = FilesSetup; + +/** + * Bringing files to Kibana + */ +export class FilesPlugin implements Plugin { + private api: undefined | FilesSetup; + + setup(core: CoreSetup): FilesSetup { + this.api = { + filesClientFactory: { + asScoped(fileKind: string) { + return createFilesClient({ fileKind, http: core.http }); + }, + }, + }; + return this.api; + } + + start(core: CoreStart): FilesStart { + return this.api!; + } +} diff --git a/x-pack/plugins/files/public/types.ts b/x-pack/plugins/files/public/types.ts new file mode 100644 index 00000000000000..a260e1e08a067e --- /dev/null +++ b/x-pack/plugins/files/public/types.ts @@ -0,0 +1,84 @@ +/* + * 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 type { + HttpApiInterfaceEntryDefinition, + CreateFileKindHttpEndpoint, + DeleteFileKindHttpEndpoint, + DownloadFileKindHttpEndpoint, + GetByIdFileKindHttpEndpoint, + ListFileKindHttpEndpoint, + UpdateFileKindHttpEndpoint, + UploadFileKindHttpEndpoint, +} from '../common/api_routes'; + +/** + * @param args - Input to the endpoint which includes body, params and query of the RESTful endpoint. + */ +type ClientMethodFrom = ( + args: E['inputs']['body'] & E['inputs']['params'] & E['inputs']['query'] +) => Promise; + +/** + * A client that can be used to manage a specific {@link FileKind}. + */ +export interface FilesClient { + /** + * Create a new file object with the provided metadata. + * + * @param args - create file args + */ + create: ClientMethodFrom; + /** + * Delete a file object and all associated share and content objects. + * + * @param args - delete file args + */ + delete: ClientMethodFrom; + /** + * Get a file object by ID. + * + * @param args - get file by ID args + */ + getById: ClientMethodFrom; + /** + * List all file objects, of a given {@link FileKind}. + * + * @param args - list files args + */ + list: ClientMethodFrom; + /** + * Update a set of of metadata values of the file object. + * + * @param args - update file args + */ + update: ClientMethodFrom; + /** + * Stream the contents of the file to Kibana server for storage. + * + * @param args - upload file args + */ + upload: ClientMethodFrom; + /** + * Stream a download of the file object's content. + * + * @param args - download file args + */ + download: ClientMethodFrom; +} + +/** + * A factory for creating a {@link FilesClient} + */ +export interface FilesClientFactory { + /** + * Create a {@link FileClient} for a given {@link FileKind}. + * + * @param fileKind - The {@link FileKind} to create a client for. + */ + asScoped(fileKind: string): FilesClient; +} diff --git a/x-pack/plugins/files/server/audit_events.ts b/x-pack/plugins/files/server/audit_events.ts new file mode 100644 index 00000000000000..ab5d33a65b7644 --- /dev/null +++ b/x-pack/plugins/files/server/audit_events.ts @@ -0,0 +1,36 @@ +/* + * 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 { EcsEventOutcome } from '@kbn/logging'; +import { AuditEvent } from '@kbn/security-plugin/server'; + +export type AuditAction = 'create' | 'delete'; + +interface CreateAuditEventArgs { + message: string; + action: AuditAction; + error?: Error; + outcome?: EcsEventOutcome; +} + +export function createAuditEvent({ + message, + action, + error, + outcome, +}: CreateAuditEventArgs): AuditEvent { + return { + message, + event: { + action, + outcome: outcome ?? error ? 'failure' : 'success', + }, + error: error && { + message: error?.message, + }, + }; +} diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/README.md b/x-pack/plugins/files/server/blob_storage_service/adapters/README.md new file mode 100644 index 00000000000000..48f9cfc5635c2b --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/README.md @@ -0,0 +1,6 @@ +The intention is that we implement any additional blob stores in this folder. + +For ex. Google, AWS and Azure all offer blob storage solutions that we can allow +our users to take advantage of. By default we store everything in Elasticsearch. + +It is not the intention that other plugins interact directly with these adapters. \ No newline at end of file diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts new file mode 100644 index 00000000000000..56f61e83e47f99 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts @@ -0,0 +1,334 @@ +/* + * 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 type { Logger } from '@kbn/core/server'; +import { set } from 'lodash'; +import { Readable } from 'stream'; +import { encode } from 'cbor-x'; +import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { ContentStream, ContentStreamEncoding, ContentStreamParameters } from './content_stream'; +import type { GetResponse } from '@elastic/elasticsearch/lib/api/types'; + +describe('ContentStream', () => { + let client: ReturnType; + let logger: Logger; + let stream: ContentStream; + + function toReadable(...args: unknown[]) { + return Readable.from([...args.map(encode)]) as unknown as GetResponse; + } + + const getContentStream = ({ + id = 'something', + index = 'somewhere', + params = { + encoding: 'base64' as ContentStreamEncoding, + size: 1, + } as ContentStreamParameters, + } = {}) => { + return new ContentStream(client, id, index, logger, params); + }; + + beforeEach(() => { + client = elasticsearchServiceMock.createClusterClient().asInternalUser; + logger = loggingSystemMock.createLogger(); + client.get.mockResponse(toReadable(set({}, '_source.data', Buffer.from('some content')))); + }); + + describe('read', () => { + beforeEach(() => { + stream = getContentStream({ params: { size: 1 } }); + }); + + it('should perform a search using index and the document id', async () => { + await new Promise((resolve) => stream.once('data', resolve)); + + expect(client.get).toHaveBeenCalledTimes(1); + + const [[request]] = client.get.mock.calls; + expect(request).toHaveProperty('index', 'somewhere'); + expect(request).toHaveProperty('id', 'something.0'); + }); + + it('should read the document contents', async () => { + const data = await new Promise((resolve) => stream.once('data', resolve)); + expect(data).toEqual(Buffer.from('some content')); + }); + + it('should be an empty stream on empty response', async () => { + client.get.mockResponseOnce(toReadable()); + const onData = jest.fn(); + + stream.on('data', onData); + await new Promise((resolve) => stream.once('end', resolve)); + + expect(onData).not.toHaveBeenCalled(); + }); + + it('should emit an error event', async () => { + client.get.mockRejectedValueOnce('some error'); + + stream.read(); + const error = await new Promise((resolve) => stream.once('error', resolve)); + + expect(error).toBe('some error'); + }); + + it('should decode base64 encoded content', async () => { + client.get.mockResponseOnce( + toReadable(set({}, '_source.data', Buffer.from('encoded content'))) + ); + const data = await new Promise((resolve) => stream.once('data', resolve)); + + expect(data).toEqual(Buffer.from('encoded content')); + }); + + it('should compound content from multiple chunks', async () => { + const [one, two, three] = ['12', '34', '56'].map(Buffer.from); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', one))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', two))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', three))); + + stream = getContentStream({ + params: { size: 6 }, + }); + + let data = ''; + for await (const chunk of stream) { + data += chunk; + } + + expect(data).toEqual('123456'); + expect(client.get).toHaveBeenCalledTimes(3); + + const [[request1], [request2], [request3]] = client.get.mock.calls; + + expect(request1).toHaveProperty('index', 'somewhere'); + expect(request1).toHaveProperty('id', 'something.0'); + expect(request2).toHaveProperty('index', 'somewhere'); + expect(request2).toHaveProperty('id', 'something.1'); + expect(request3).toHaveProperty('index', 'somewhere'); + expect(request3).toHaveProperty('id', 'something.2'); + }); + + it('should stop reading on empty chunk', async () => { + const [one, two, three] = ['12', '34', ''].map(Buffer.from); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', one))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', two))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', three))); + stream = getContentStream({ params: { size: 12 } }); + let data = ''; + for await (const chunk of stream) { + data += chunk; + } + + expect(data).toEqual('1234'); + expect(client.get).toHaveBeenCalledTimes(3); + }); + + it('should read while chunks are present when there is no size', async () => { + const [one, two] = ['12', '34'].map(Buffer.from); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', one))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', two))); + client.get.mockResponseOnce(toReadable({})); + stream = getContentStream({ params: { size: undefined } }); + let data = ''; + for await (const chunk of stream) { + data += chunk; + } + + expect(data).toEqual('1234'); + expect(client.get).toHaveBeenCalledTimes(3); + }); + + it('should decode every chunk separately', async () => { + const [one, two, three, four] = ['12', '34', '56', ''].map(Buffer.from); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', one))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', two))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', three))); + client.get.mockResponseOnce(toReadable(set({}, '_source.data', four))); + stream = getContentStream({ params: { size: 12 } }); + let data = ''; + for await (const chunk of stream) { + data += chunk; + } + + expect(data).toEqual('123456'); + }); + }); + + describe('write', () => { + beforeEach(() => { + stream = getContentStream({ params: { size: 1 } }); + }); + it('should not send a request until stream is closed', () => { + stream.write('something'); + + expect(client.update).not.toHaveBeenCalled(); + }); + + it('should provide a document ID after writing to a destination', async () => { + stream = new ContentStream(client, undefined, 'somewhere', logger); + expect(stream.getContentReferenceId()).toBe(undefined); + stream.end('some data'); + await new Promise((resolve) => stream.once('finish', resolve)); + expect(stream.getContentReferenceId()).toEqual(expect.any(String)); + }); + + it('should send the contents when stream ends', async () => { + stream.write('123'); + stream.write('456'); + stream.end(); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(client.index).toHaveBeenCalledTimes(1); + + const [[request]] = client.index.mock.calls; + + expect(request).toHaveProperty('id', 'something.0'); + expect(request).toHaveProperty('index', 'somewhere'); + expect(request).toHaveProperty( + 'document', + encode({ data: Buffer.from('123456'), bid: 'something', last: true }) + ); + }); + + it('should update a number of written bytes', async () => { + stream.write('123'); + stream.write('456'); + stream.end(); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(stream.bytesWritten).toBe(6); + }); + + it('should emit an error event', async () => { + client.index.mockRejectedValueOnce('some error'); + + stream.end('data'); + const error = await new Promise((resolve) => stream.once('error', resolve)); + + expect(error).toBe('some error'); + }); + + it('should remove all previous chunks before writing', async () => { + stream.end('12345'); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(client.deleteByQuery).toHaveBeenCalledTimes(1); + + const [[request]] = client.deleteByQuery.mock.calls; + + expect(request).toHaveProperty('index', 'somewhere'); + expect(request).toHaveProperty('query.bool.must.match.bid', 'something'); + }); + + it('should split data into chunks', async () => { + stream = getContentStream({ params: { maxChunkSize: '3B' } }); + stream.end('123456789'); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(client.index).toHaveBeenCalledTimes(3); + expect(client.index).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + document: encode({ data: Buffer.from('123'), bid: 'something' }), + id: 'something.0', + index: 'somewhere', + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + expect(client.index).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + id: 'something.1', + index: 'somewhere', + document: encode({ data: Buffer.from('456'), bid: 'something' }), + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + expect(client.index).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + id: 'something.2', + index: 'somewhere', + document: encode({ data: Buffer.from('789'), bid: 'something', last: true }), + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + }); + + it('should encode every chunk separately', async () => { + stream = getContentStream({ params: { maxChunkSize: '3B' } }); + stream.end('12345678'); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(client.index).toHaveBeenCalledTimes(3); + expect(client.index).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + id: 'something.0', + index: 'somewhere', + document: encode({ + data: Buffer.from('123'), + bid: 'something', + }), + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + expect(client.index).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + id: 'something.1', + index: 'somewhere', + document: encode({ + data: Buffer.from('456'), + bid: 'something', + }), + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + expect(client.index).toHaveBeenNthCalledWith( + 3, + expect.objectContaining({ + id: 'something.2', + index: 'somewhere', + document: encode({ + data: Buffer.from('78'), + bid: 'something', + last: true, + }), + }), + expect.objectContaining({ + headers: { accept: 'application/json', 'content-type': 'application/cbor' }, + }) + ); + }); + + it('should clear the job contents on writing empty data', async () => { + stream.end(); + await new Promise((resolve) => stream.once('finish', resolve)); + + expect(client.deleteByQuery).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(0); + + const [[deleteRequest]] = client.deleteByQuery.mock.calls; + + expect(deleteRequest).toHaveProperty('query.bool.must.match.bid', 'something'); + }); + }); +}); diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts new file mode 100644 index 00000000000000..746c66798b5e8a --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts @@ -0,0 +1,382 @@ +/* + * 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 cuid from 'cuid'; +import * as cborx from 'cbor-x'; +import { errors as esErrors } from '@elastic/elasticsearch'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { ByteSizeValue } from '@kbn/config-schema'; +import { defaults } from 'lodash'; +import { Duplex, Writable, Readable } from 'stream'; + +import type { FileChunkDocument } from '../mappings'; + +type Callback = (error?: Error) => void; + +export type ContentStreamEncoding = 'base64' | 'raw'; + +interface IndexRequestParams { + data: Buffer; + id: string; + index: string; + bid: string; +} + +export interface ContentStreamParameters { + /** + * The maximum size allowed per chunk. + * + * @default 4mb + */ + maxChunkSize?: string; + /** + * The file size in bytes. This can be used to optimize downloading. + */ + size?: number; +} + +export class ContentStream extends Duplex { + private buffers: Buffer[] = []; + private bytesBuffered = 0; + + private bytesRead = 0; + private chunksRead = 0; + private chunksWritten = 0; + private maxChunkSize?: number; + private parameters: Required; + + /** + * The number of bytes written so far. + * Does not include data that is still queued for writing. + */ + bytesWritten = 0; + + constructor( + private readonly client: ElasticsearchClient, + private id: undefined | string, + private readonly index: string, + private readonly logger: Logger, + parameters: ContentStreamParameters = {} + ) { + super(); + this.parameters = defaults(parameters, { + encoding: 'base64', + size: -1, + maxChunkSize: '4mb', + }); + } + + private getMaxContentSize(): number { + return ByteSizeValue.parse(this.parameters.maxChunkSize).getValueInBytes(); + } + + private getMaxChunkSize() { + if (!this.maxChunkSize) { + this.maxChunkSize = this.getMaxContentSize(); + this.logger.debug(`Chunk size is ${this.maxChunkSize} bytes.`); + } + + return this.maxChunkSize; + } + + private async readChunk(): Promise<[data: null | Buffer, last?: boolean]> { + if (!this.id) { + throw new Error('No document ID provided. Cannot read chunk.'); + } + const id = this.getChunkId(this.chunksRead); + + this.logger.debug(`Reading chunk #${this.chunksRead}.`); + + try { + const stream = await this.client.get( + { + id, + index: this.index, + _source_includes: ['data', 'last'], + }, + { + asStream: true, // This tells the ES client to not process the response body in any way. + headers: { accept: 'application/cbor' }, + } + ); + + const chunks: Buffer[] = []; + for await (const chunk of stream as unknown as Readable) { + chunks.push(chunk); + } + const buffer = Buffer.concat(chunks); + const source: undefined | FileChunkDocument = buffer.byteLength + ? cborx.decode(Buffer.concat(chunks))?._source + : undefined; + + const dataBuffer = source?.data as unknown as Buffer; + return [dataBuffer?.byteLength ? dataBuffer : null, source?.last]; + } catch (e) { + if (e instanceof esErrors.ResponseError && e.statusCode === 404) { + const readingHeadChunk = this.chunksRead <= 0; + if (this.isSizeUnknown() && !readingHeadChunk) { + // Assume there is no more content to read. + return [null]; + } + if (readingHeadChunk) { + this.logger.error(`File not found (id: ${this.getHeadChunkId()}).`); + } + } + throw e; + } + } + + private isSizeUnknown(): boolean { + return this.parameters.size < 0; + } + + private isRead() { + const { size } = this.parameters; + if (size > 0) { + return this.bytesRead >= size; + } + return false; + } + + _read() { + this.readChunk() + .then(([buffer, last]) => { + if (!buffer) { + this.logger.debug(`Chunk is empty.`); + this.push(null); + return; + } + + this.push(buffer); + this.chunksRead++; + this.bytesRead += buffer.byteLength; + + if (this.isRead() || last) { + this.logger.debug(`Read ${this.bytesRead} of ${this.parameters.size} bytes.`); + this.push(null); + } + }) + .catch((err) => this.destroy(err)); + } + + private async removeChunks() { + const bid = this.getId(); + this.logger.debug(`Clearing existing chunks for ${bid}`); + await this.client.deleteByQuery({ + index: this.index, + ignore_unavailable: true, + query: { + bool: { + must: { match: { bid } }, + }, + }, + }); + } + + private getId(): string { + if (!this.id) { + this.id = cuid(); + } + return this.id; + } + + private getHeadChunkId() { + return `${this.getId()}.0`; + } + + private getChunkId(chunkNumber = 0) { + return chunkNumber === 0 ? this.getHeadChunkId() : `${this.getId()}.${chunkNumber}`; + } + + private async indexChunk({ bid, data, id, index }: IndexRequestParams, last?: true) { + await this.client.index( + { + id, + index, + document: cborx.encode( + last + ? { + data, + bid, + last, + } + : { data, bid } + ), + }, + { + headers: { + 'content-type': 'application/cbor', + accept: 'application/json', + }, + } + ); + } + + /** + * Holds a reference to the last written chunk without actually writing it to ES. + * + * This enables us to reliably determine what the real last chunk is at the cost + * of holding, at most, 2 full chunks in memory. + */ + private indexRequestBuffer: undefined | IndexRequestParams; + private async writeChunk(data: Buffer) { + const chunkId = this.getChunkId(this.chunksWritten); + + if (!this.indexRequestBuffer) { + this.indexRequestBuffer = { + id: chunkId, + index: this.index, + data, + bid: this.getId(), + }; + return; + } + + this.logger.debug(`Writing chunk with ID "${this.indexRequestBuffer.id}".`); + await this.indexChunk(this.indexRequestBuffer); + // Hold a reference to the next buffer now that we indexed the previous one. + this.indexRequestBuffer = { + id: chunkId, + index: this.index, + data, + bid: this.getId(), + }; + } + + private async finalizeLastChunk() { + if (!this.indexRequestBuffer) { + return; + } + this.logger.debug(`Writing last chunk with id "${this.indexRequestBuffer.id}".`); + await this.indexChunk(this.indexRequestBuffer, true); + this.indexRequestBuffer = undefined; + } + + private async flush(size = this.bytesBuffered) { + const buffersToFlush: Buffer[] = []; + let bytesToFlush = 0; + + /* + Loop over each buffer, keeping track of how many bytes we have added + to the array of buffers to be flushed. The array of buffers to be flushed + contains buffers by reference, not copies. This avoids putting pressure on + the CPU for copying buffers or for gc activity. Please profile performance + with a large byte configuration and a large number of records (900k+) + before changing this code. + */ + while (this.buffers.length) { + const remainder = size - bytesToFlush; + if (remainder <= 0) { + break; + } + const buffer = this.buffers.shift()!; + const chunkedBuffer = buffer.slice(0, remainder); + buffersToFlush.push(chunkedBuffer); + bytesToFlush += chunkedBuffer.byteLength; + + if (buffer.byteLength > remainder) { + this.buffers.unshift(buffer.slice(remainder)); + } + } + + // We call Buffer.concat with the fewest number of buffers possible + const chunk = Buffer.concat(buffersToFlush); + + if (!this.chunksWritten) { + await this.removeChunks(); + } + if (chunk.byteLength) { + await this.writeChunk(chunk); + this.chunksWritten++; + } + + this.bytesWritten += chunk.byteLength; + this.bytesBuffered -= bytesToFlush; + } + + private async flushAllFullChunks() { + const maxChunkSize = this.getMaxChunkSize(); + + while (this.bytesBuffered >= maxChunkSize && this.buffers.length) { + await this.flush(maxChunkSize); + } + } + + _write(chunk: Buffer | string, encoding: BufferEncoding, callback: Callback) { + const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding); + this.bytesBuffered += buffer.byteLength; + this.buffers.push(buffer); + + this.flushAllFullChunks() + .then(() => callback()) + .catch(callback); + } + + _final(callback: Callback) { + this.flush() + .then(() => this.finalizeLastChunk()) + .then(() => callback()) + .catch(callback); + } + + /** + * This ID can be used to retrieve or delete all of the file chunks but does + * not necessarily correspond to an existing document. + * + * @note do not use this ID with anything other than a {@link ContentStream} + * compatible implementation for reading blob-like structures from ES. + * + * @note When creating a new blob, this value may be undefined until the first + * chunk is written. + */ + public getContentReferenceId(): undefined | string { + return this.id; + } + + public getBytesWritten(): number { + return this.bytesWritten; + } +} + +export interface ContentStreamArgs { + client: ElasticsearchClient; + /** + * Provide base ID from which all chunks derive their IDs. + */ + id?: string; + + /** + * The Elasticsearch index name to read from or write to. + */ + index: string; + + /** + * Known size of the file we are reading. This value can be used to optimize + * reading of the file. + */ + logger: Logger; + parameters?: ContentStreamParameters; +} + +function getContentStream({ client, id, index, logger, parameters }: ContentStreamArgs) { + return new ContentStream(client, id, index, logger, parameters); +} + +export type WritableContentStream = Writable & + Pick; + +export function getWritableContentStream(args: ContentStreamArgs): WritableContentStream { + return getContentStream(args); +} + +export type ReadableContentStream = Readable; + +export function getReadableContentStream( + args: Omit & { id: string } +): ReadableContentStream { + return getContentStream(args); +} diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/index.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/index.ts new file mode 100644 index 00000000000000..a31e0c8b672dcb --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/content_stream/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + ContentStream, + getReadableContentStream, + getWritableContentStream, +} from './content_stream'; + +export type { + ContentStreamArgs, + ContentStreamEncoding, + ContentStreamParameters, + ReadableContentStream, + WritableContentStream, +} from './content_stream'; diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/es.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/es.ts new file mode 100644 index 00000000000000..5074ab12bdfc75 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/es.ts @@ -0,0 +1,139 @@ +/* + * 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 assert from 'assert'; +import { once } from 'lodash'; +import { errors } from '@elastic/elasticsearch'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { Readable, Transform } from 'stream'; +import { pipeline } from 'stream/promises'; +import { promisify } from 'util'; +import type { BlobStorageClient } from '../../types'; +import type { ReadableContentStream } from './content_stream'; +import { getReadableContentStream, getWritableContentStream } from './content_stream'; +import { mappings } from './mappings'; + +/** + * Export this value for convenience to be used in tests. Do not use outside of + * this adapter. + * @internal + */ +export const BLOB_STORAGE_SYSTEM_INDEX_NAME = '.kibana_blob_storage'; + +export const MAX_BLOB_STORE_SIZE_BYTES = 50 * 1024 * 1024 * 1024; // 50 GiB + +export class ElasticsearchBlobStorageClient implements BlobStorageClient { + constructor( + private readonly esClient: ElasticsearchClient, + private readonly index: string = BLOB_STORAGE_SYSTEM_INDEX_NAME, + private readonly chunkSize: undefined | string, + private readonly logger: Logger + ) { + assert( + this.index.startsWith('.kibana'), + `Elasticsearch blob store index name must start with ".kibana", got ${this.index}.` + ); + } + + /** + * @note + * There is a known issue where calling this function simultaneously can result + * in a race condition where one of the calls will fail because the index is already + * being created. + * + * This is only an issue for the very first time the index is being created. + */ + private createIndexIfNotExists = once(async (): Promise => { + try { + const index = this.index; + if (await this.esClient.indices.exists({ index })) { + this.logger.debug(`${index} already exists.`); + return; + } + + this.logger.info(`Creating ${index} for Elasticsearch blob store.`); + + await this.esClient.indices.create({ + index, + body: { + settings: { + number_of_shards: 1, + auto_expand_replicas: '0-1', + }, + mappings, + }, + }); + } catch (e) { + if (e instanceof errors.ResponseError && e.statusCode === 400) { + this.logger.warn('Unable to create blob storage index, it may have been created already.'); + } + // best effort + } + }); + + public async upload( + src: Readable, + { transforms, id }: { transforms?: Transform[]; id?: string } = {} + ): Promise<{ id: string; size: number }> { + await this.createIndexIfNotExists(); + + try { + const dest = getWritableContentStream({ + id, + client: this.esClient, + index: this.index, + logger: this.logger.get('content-stream-upload'), + parameters: { + maxChunkSize: this.chunkSize, + }, + }); + await pipeline.apply(null, [src, ...(transforms ?? []), dest] as unknown as Parameters< + typeof pipeline + >); + + return { + id: dest.getContentReferenceId()!, + size: dest.getBytesWritten(), + }; + } catch (e) { + this.logger.error(`Could not write chunks to Elasticsearch: ${e}`); + throw e; + } + } + + private getReadableContentStream(id: string, size?: number): ReadableContentStream { + return getReadableContentStream({ + id, + client: this.esClient, + index: this.index, + logger: this.logger.get('content-stream-download'), + parameters: { + size, + }, + }); + } + + public async download({ id, size }: { id: string; size?: number }): Promise { + return this.getReadableContentStream(id, size); + } + + public async delete(id: string): Promise { + try { + const dest = getWritableContentStream({ + id, + client: this.esClient, + index: this.index, + logger: this.logger.get('content-stream-delete'), + }); + /** @note Overwriting existing content with an empty buffer to remove all the chunks. */ + await promisify(dest.end.bind(dest, '', 'utf8'))(); + } catch (e) { + this.logger.error(`Could not delete file: ${e}`); + throw e; + } + } +} diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/index.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/index.ts new file mode 100644 index 00000000000000..75ac82acb66df5 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { ElasticsearchBlobStorageClient, MAX_BLOB_STORE_SIZE_BYTES } from './es'; diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts new file mode 100644 index 00000000000000..b947c980164fcd --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts @@ -0,0 +1,162 @@ +/* + * 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 sinon from 'sinon'; +import { ElasticsearchClient } from '@kbn/core/server'; +import { Readable } from 'stream'; +import { + createTestServers, + TestElasticsearchUtils, + TestKibanaUtils, +} from '@kbn/core/test_helpers/kbn_server'; + +import { ElasticsearchBlobStorageClient, BLOB_STORAGE_SYSTEM_INDEX_NAME } from '../es'; + +describe('Elasticsearch blob storage', () => { + let manageES: TestElasticsearchUtils; + let manageKbn: TestKibanaUtils; + let esBlobStorage: ElasticsearchBlobStorageClient; + let esClient: ElasticsearchClient; + const sandbox = sinon.createSandbox(); + + beforeAll(async () => { + const { startES, startKibana } = createTestServers({ adjustTimeout: jest.setTimeout }); + manageES = await startES(); + manageKbn = await startKibana(); + esClient = manageKbn.coreStart.elasticsearch.client.asInternalUser; + }); + + afterAll(async () => { + await manageKbn.root.shutdown(); + await manageKbn.stop(); + await manageES.stop(); + }); + + const createEsBlobStorage = ({ chunkSize }: { chunkSize?: string } = {}) => + new ElasticsearchBlobStorageClient( + esClient, + undefined, + chunkSize, + manageKbn.root.logger.get('es-blob-test') + ); + + beforeEach(() => { + esBlobStorage = createEsBlobStorage(); + sandbox.spy(esClient, 'get'); + }); + + afterEach(async () => { + await esClient.indices.delete({ index: BLOB_STORAGE_SYSTEM_INDEX_NAME }); + sandbox.restore(); + }); + + it('sets up a new blob storage index after first write', async () => { + expect(await esClient.indices.exists({ index: BLOB_STORAGE_SYSTEM_INDEX_NAME })).toBe(false); + await esBlobStorage.upload(Readable.from(['upload this'])); + expect(await esClient.indices.exists({ index: BLOB_STORAGE_SYSTEM_INDEX_NAME })).toBe(true); + }); + + it('uploads and retrieves file content of known size', async () => { + const { id, size } = await esBlobStorage.upload(Readable.from(['upload this'])); + const rs = await esBlobStorage.download({ id, size }); + const chunks: string[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(chunks.join('')).toBe('upload this'); + expect((esClient.get as sinon.SinonSpy).calledOnce).toBe(true); + }); + + /** + * Test a case where, if, for whatever reason, the file size is unknown we should + * still be able to download the file. + */ + it('uploads and retrieves file content of unknown size', async () => { + const { id } = await esBlobStorage.upload(Readable.from(['upload this'])); + const rs = await esBlobStorage.download({ id }); + const chunks: string[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(chunks.join('')).toBe('upload this'); + // Called once because we should have found 'last: true' + expect((esClient.get as sinon.SinonSpy).calledOnce).toBe(true); + expect((esClient.get as sinon.SinonSpy).args[0]).toEqual([ + { + id: id + '.0', + index: BLOB_STORAGE_SYSTEM_INDEX_NAME, + _source_includes: ['data', 'last'], + }, + { + headers: { accept: 'application/cbor' }, + asStream: true, + }, + ]); + }); + + it('uploads and downloads a file of many chunks', async () => { + const fileString = Buffer.alloc(36 * 1028, 'a'); + esBlobStorage = createEsBlobStorage({ chunkSize: '1024B' }); + const { id } = await esBlobStorage.upload(Readable.from([fileString])); + expect(await getAllDocCount()).toMatchObject({ count: 37 }); + const rs = await esBlobStorage.download({ id }); + const chunks: string[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(chunks.join('')).toBe(fileString.toString('utf-8')); + }); + + const getAllDocCount = async () => { + await esClient.indices.refresh({ index: BLOB_STORAGE_SYSTEM_INDEX_NAME }); + return esClient.count({ + index: BLOB_STORAGE_SYSTEM_INDEX_NAME, + query: { match_all: {} }, + }); + }; + + it('uploads and removes file content', async () => { + const { id } = await esBlobStorage.upload(Readable.from(['upload this'])); + expect(await getAllDocCount()).toMatchObject({ count: 1 }); + await esBlobStorage.delete(id); + expect(await getAllDocCount()).toMatchObject({ count: 0 }); + }); + + it('chunks files and then deletes all chunks when cleaning up', async () => { + const oneMiB = 1024 * 1024; + const fileString = Buffer.alloc(31 * oneMiB, 'a'); + const fileString2 = Buffer.alloc(8 * oneMiB, 'b'); + + esBlobStorage = createEsBlobStorage(); + const { id } = await esBlobStorage.upload(Readable.from([fileString])); + const { id: id2 } = await esBlobStorage.upload(Readable.from([fileString2])); + expect(await getAllDocCount()).toMatchObject({ count: 10 }); + await esBlobStorage.delete(id); + expect(await getAllDocCount()).toMatchObject({ count: 2 }); + // Now we check that the other file is still intact + const rs = await esBlobStorage.download({ id: id2 }); + const chunks: Buffer[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + const resultString = chunks.join(''); + expect(resultString).toBe(fileString2.toString('utf-8')); + }); + + it('stores chunks at exactly max chunk size', async () => { + esBlobStorage = createEsBlobStorage({ chunkSize: '1024B' }); + const fileBuffer = Buffer.alloc(2048, 'a'); + const { id } = await esBlobStorage.upload(Readable.from([fileBuffer])); + expect(await getAllDocCount()).toMatchObject({ count: 2 }); + const rs = await esBlobStorage.download({ id }); + const chunks: Buffer[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(chunks.join('')).toEqual(fileBuffer.toString('utf-8')); + }); +}); diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/es/mappings.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/es/mappings.ts new file mode 100644 index 00000000000000..dbcd57a06ba184 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/es/mappings.ts @@ -0,0 +1,43 @@ +/* + * 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 type { + MappingTypeMapping, + MappingProperty, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +/** + * These are the fields we expect to find a given document acting as a file chunk. + * + * @note not all fields are used by this adapter but this represents the standard + * shape for any consumers of BlobStorage in ES. + */ +export interface FileChunkDocument { + /** + * Data contents. Could be part of a file (chunk) or the entire file. + */ + data: string; + + /** + * Blob ID field that tags a set of blobs as belonging to the same file. + */ + bid: string; + + /** + * Whether this is the last chunk in a sequence. + */ + last?: boolean; +} + +export const mappings: MappingTypeMapping = { + dynamic: false, + properties: { + data: { type: 'binary' }, // Binary fields are automatically marked as not searchable by ES + bid: { type: 'keyword', index: false }, + last: { type: 'boolean', index: false }, + } as Record, // Ensure that our ES types and TS types stay somewhat in sync +} as const; diff --git a/x-pack/plugins/files/server/blob_storage_service/adapters/index.ts b/x-pack/plugins/files/server/blob_storage_service/adapters/index.ts new file mode 100644 index 00000000000000..75ac82acb66df5 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/adapters/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { ElasticsearchBlobStorageClient, MAX_BLOB_STORE_SIZE_BYTES } from './es'; diff --git a/x-pack/plugins/files/server/blob_storage_service/blob_storage_service.ts b/x-pack/plugins/files/server/blob_storage_service/blob_storage_service.ts new file mode 100644 index 00000000000000..0bc1c632e2c324 --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/blob_storage_service.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { BlobStorageSettings, ES_FIXED_SIZE_INDEX_BLOB_STORE } from '../../common'; +import { BlobStorageClient } from './types'; +import { ElasticsearchBlobStorageClient, MAX_BLOB_STORE_SIZE_BYTES } from './adapters'; + +interface ElasticsearchBlobStorageSettings { + index?: string; + chunkSize?: string; +} + +export class BlobStorageService { + constructor(private readonly esClient: ElasticsearchClient, private readonly logger: Logger) {} + + private createESBlobStorage({ + index, + chunkSize, + }: ElasticsearchBlobStorageSettings): BlobStorageClient { + return new ElasticsearchBlobStorageClient( + this.esClient, + index, + chunkSize, + this.logger.get('elasticsearch-blob-storage') + ); + } + + public createBlobStorageClient(args?: BlobStorageSettings): BlobStorageClient { + return this.createESBlobStorage({ ...args?.esFixedSizeIndex }); + } + + public getStaticBlobStorageSettings() { + return { + [ES_FIXED_SIZE_INDEX_BLOB_STORE]: { + capacity: MAX_BLOB_STORE_SIZE_BYTES, + }, + }; + } +} diff --git a/x-pack/plugins/files/server/blob_storage_service/index.ts b/x-pack/plugins/files/server/blob_storage_service/index.ts new file mode 100644 index 00000000000000..fd8d4e190c092e --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/index.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { BlobStorageService } from './blob_storage_service'; +export { ElasticsearchBlobStorageClient } from './adapters'; +export type { BlobStorageClient, UploadOptions } from './types'; diff --git a/x-pack/plugins/files/server/blob_storage_service/types.ts b/x-pack/plugins/files/server/blob_storage_service/types.ts new file mode 100644 index 00000000000000..6a5c40708a973b --- /dev/null +++ b/x-pack/plugins/files/server/blob_storage_service/types.ts @@ -0,0 +1,73 @@ +/* + * 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 type { JsonValue } from '@kbn/utility-types'; +import type { Readable, Transform } from 'stream'; + +export type BlobAttribute = [key: string, value: JsonValue]; + +export interface UploadOptions { + /** + * Optionally provide any transforms to run on the readable source stream + * as it is being uploaded. + */ + transforms?: Transform[]; + + /** + * The ID to use to derive blob IDs. + * + * If "mycoolid" is provided. The blob IDs will look like: + * "mycoolid.0" + * "mycoolid.1" + * "mycoolid.2" + * + * And so on. + */ + id?: string; +} + +/** + * An interface that must be implemented by any blob storage adapter. + * + * @note + * The blob storage target must be fully managed by Kibana through this interface + * to avoid corrupting stored data. + * + * @note + * File IDs are stored in Kibana Saved Objects as references to a file. + * + * @internal + */ +export interface BlobStorageClient { + /** + * Upload a new file. + * + * Generates a random file ID and returns it upon successfully uploading a + * file. The file size can be used when downloading the file later. + * + * @param content - The readable stream to upload. + * @param opts - Optional options to use when uploading the file. + */ + upload(content: Readable, opts?: UploadOptions): Promise<{ id: string; size: number }>; + + /** + * Download a file. + * + * Given an ID, and optional file size, retrieve the file contents as a readable + * stream. + * + * @param args - Arguments to download a file + */ + download(args: { id: string; size?: number }): Promise; + + /** + * Delete a file given a unique ID. + * + * @param id - The ID of the file to delete. + */ + delete(id: string): Promise; +} diff --git a/x-pack/plugins/files/server/file/errors.ts b/x-pack/plugins/files/server/file/errors.ts new file mode 100644 index 00000000000000..d0d0eef84c0526 --- /dev/null +++ b/x-pack/plugins/files/server/file/errors.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable max-classes-per-file */ + +class FileError extends Error { + constructor(message?: string) { + super(message); + Error.captureStackTrace(this); + } +} + +export class ContentAlreadyUploadedError extends FileError {} +export class NoDownloadAvailableError extends FileError {} +export class UploadInProgressError extends FileError {} +export class AlreadyDeletedError extends FileError {} diff --git a/x-pack/plugins/files/server/file/file.test.ts b/x-pack/plugins/files/server/file/file.test.ts new file mode 100644 index 00000000000000..ebb1efe32422c1 --- /dev/null +++ b/x-pack/plugins/files/server/file/file.test.ts @@ -0,0 +1,85 @@ +/* + * 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 type { ElasticsearchClient, ISavedObjectsRepository } from '@kbn/core/server'; +import { createSandbox } from 'sinon'; +import { + elasticsearchServiceMock, + loggingSystemMock, + savedObjectsServiceMock, + httpServiceMock, +} from '@kbn/core/server/mocks'; +import { Readable } from 'stream'; +import { promisify } from 'util'; + +const setImmediate = promisify(global.setImmediate); + +import { BlobStorageService } from '../blob_storage_service'; +import { InternalFileService } from '../file_service/internal_file_service'; +import { + FileKindsRegistryImpl, + getFileKindsRegistry, + setFileKindsRegistry, +} from '../file_kinds_registry'; +import { InternalFileShareService } from '../file_share_service'; +import { FileMetadataClient } from '../file_client'; +import { SavedObjectsFileMetadataClient } from '../file_client/file_metadata_client/adapters/saved_objects'; + +describe('File', () => { + let esClient: ElasticsearchClient; + let fileService: InternalFileService; + let blobStorageService: BlobStorageService; + let fileShareService: InternalFileShareService; + let soClient: ISavedObjectsRepository; + let fileMetadaClient: FileMetadataClient; + + const sandbox = createSandbox(); + const fileKind = 'fileKind'; + + beforeAll(() => { + setFileKindsRegistry(new FileKindsRegistryImpl(httpServiceMock.createRouter())); + getFileKindsRegistry().register({ http: {}, id: fileKind }); + }); + + beforeEach(() => { + const logger = loggingSystemMock.createLogger(); + esClient = elasticsearchServiceMock.createInternalClient(); + soClient = savedObjectsServiceMock.createStartContract().createInternalRepository(); + fileMetadaClient = new SavedObjectsFileMetadataClient('test', soClient, logger); + blobStorageService = new BlobStorageService(esClient, logger); + fileShareService = new InternalFileShareService(soClient); + fileService = new InternalFileService( + fileMetadaClient, + blobStorageService, + fileShareService, + undefined, + getFileKindsRegistry(), + logger + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + sandbox.restore(); + }); + + it('deletes file content when an upload fails', async () => { + const createBlobSpy = sandbox.spy(blobStorageService, 'createBlobStorageClient'); + + (esClient.index as jest.Mock).mockRejectedValue(new Error('test')); + const fileSO = { attributes: { Status: 'AWAITING_UPLOAD' } }; + (soClient.create as jest.Mock).mockResolvedValue(fileSO); + (soClient.update as jest.Mock).mockResolvedValue(fileSO); + + const file = await fileService.createFile({ name: 'test', fileKind }); + const [{ returnValue: blobStore }] = createBlobSpy.getCalls(); + const blobStoreSpy = sandbox.spy(blobStore, 'delete'); + expect(blobStoreSpy.calledOnce).toBe(false); + await expect(file.uploadContent(Readable.from(['test']))).rejects.toThrow(new Error('test')); + await setImmediate(); + expect(blobStoreSpy.calledOnce).toBe(true); + }); +}); diff --git a/x-pack/plugins/files/server/file/file.ts b/x-pack/plugins/files/server/file/file.ts new file mode 100644 index 00000000000000..00544a7e14f082 --- /dev/null +++ b/x-pack/plugins/files/server/file/file.ts @@ -0,0 +1,267 @@ +/* + * 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 { Logger } from '@kbn/core/server'; +import mimeType from 'mime'; +import { Readable } from 'stream'; +import type { FileCompression, FileShareJSON, FileShareJSONWithToken } from '../../common/types'; +import type { + File as IFile, + FileKind, + FileMetadata, + FileStatus, + UpdatableFileMetadata, + FileJSON, +} from '../../common'; +import { + fileAttributesReducer, + Action, + createDefaultFileAttributes, +} from './file_attributes_reducer'; +import { createAuditEvent } from '../audit_events'; +import { InternalFileService } from '../file_service/internal_file_service'; +import { InternalFileShareService } from '../file_share_service'; +import type { FileClientImpl } from '../file_client/file_client'; +import { toJSON } from './to_json'; +import { + AlreadyDeletedError, + ContentAlreadyUploadedError, + NoDownloadAvailableError, + UploadInProgressError, +} from './errors'; + +/** + * Public class that provides all data and functionality consumers will need at the + * individual file level + * + * @note Instantiation should not happen outside of this plugin + */ +export class File implements IFile { + private readonly logAuditEvent: InternalFileService['writeAuditLog']; + + constructor( + public readonly id: string, + private fileMetadata: FileMetadata, + private readonly fileClient: FileClientImpl, + private readonly internalFileService: InternalFileService, + private readonly fileShareService: InternalFileShareService, + private readonly logger: Logger + ) { + this.logAuditEvent = this.internalFileService.writeAuditLog.bind(this.internalFileService); + } + + private async updateFileState(action: Action) { + const { metadata } = await this.fileClient.update({ + id: this.id, + metadata: fileAttributesReducer(this.metadata, action), + }); + this.fileMetadata = metadata; + } + + private isReady(): boolean { + return this.status === 'READY'; + } + + private isDeleted(): boolean { + return this.status === 'DELETED'; + } + + private uploadInProgress(): boolean { + return this.status === 'UPLOADING'; + } + + public async update(attrs: Partial): Promise { + await this.updateFileState({ + action: 'updateFile', + payload: attrs, + }); + return this; + } + + public async uploadContent(content: Readable): Promise { + if (this.uploadInProgress()) { + throw new UploadInProgressError('Upload already in progress.'); + } + if (this.isReady()) { + throw new ContentAlreadyUploadedError('Already uploaded file content.'); + } + this.logger.debug(`Uploading file [id = ${this.id}][name = ${this.name}].`); + await this.updateFileState({ + action: 'uploading', + }); + + try { + const { size } = await this.fileClient.upload(this.id, content); + await this.updateFileState({ + action: 'uploaded', + payload: { size }, + }); + } catch (e) { + await this.updateFileState({ action: 'uploadError' }); + this.fileClient.deleteContent(this.id).catch(() => {}); // Best effort to remove any uploaded content + throw e; + } + } + + public downloadContent(): Promise { + const { size } = this.metadata; + if (!this.isReady()) { + throw new NoDownloadAvailableError('This file content is not available for download.'); + } + // We pass through this file ID to retrieve blob content. + return this.fileClient.download({ id: this.id, size }); + } + + public async delete(): Promise { + if (this.uploadInProgress()) { + throw new UploadInProgressError('Cannot delete file while upload in progress'); + } + if (this.isDeleted()) { + throw new AlreadyDeletedError('File has already been deleted'); + } + await this.updateFileState({ + action: 'delete', + }); + // Stop sharing this file + await this.fileShareService.deleteForFile({ file: this }); + await this.fileClient.delete({ id: this.id, hasContent: this.isReady() }); + this.logAuditEvent( + createAuditEvent({ + action: 'delete', + outcome: 'success', + message: `Deleted file "${this.name}" of kind "${this.fileKind}" with id "${this.id}"`, + }) + ); + } + + public async share({ + name, + validUntil, + }: { + name?: string; + validUntil?: number; + }): Promise { + const shareObject = await this.fileShareService.share({ file: this, name, validUntil }); + this.internalFileService.writeAuditLog( + createAuditEvent({ + action: 'create', + message: `Shared file "${this.name}" with id "${this.id}"`, + }) + ); + return shareObject; + } + + async listShares(): Promise { + const { shares } = await this.fileShareService.list({ fileId: this.id }); + return shares; + } + + async unshare(opts: { shareId: string }): Promise { + await this.fileShareService.delete({ id: opts.shareId }); + this.internalFileService.writeAuditLog( + createAuditEvent({ + action: 'delete', + message: `Removed share for "${this.name}" with id "${this.id}"`, + }) + ); + } + + public toJSON(): FileJSON { + return toJSON(this.id, this.metadata); + } + + private get metadata(): FileMetadata { + return this.fileMetadata; + } + + public get created(): string { + return this.metadata.created; + } + + public get updated(): string { + return this.metadata.Updated; + } + + public get chunkSize(): number | undefined { + return this.metadata.ChunkSize; + } + + public get fileKind(): string { + return this.fileClient.fileKind; + } + + public get name(): string { + return this.metadata.name; + } + + public get status(): FileStatus { + return this.metadata.Status; + } + + public get compression(): undefined | FileCompression { + return this.metadata.Compression; + } + + public get size(): undefined | number { + return this.metadata.size; + } + + public get meta(): M { + return this.metadata.Meta as M; + } + + public get alt(): undefined | string { + return this.metadata.Alt; + } + + public get mimeType(): undefined | string { + return this.metadata.mime_type; + } + + public get extension(): undefined | string { + return this.metadata.extension; + } + + /** + * Static method for creating files so that we can keep all of the audit logging for files + * in the same place. + */ + public static async create( + { + name, + fileKind, + alt, + meta, + mime, + }: { name: string; fileKind: FileKind; alt?: string; meta?: unknown; mime?: string }, + internalFileService: InternalFileService, + fileClient: FileClientImpl + ) { + const fileMeta = await fileClient.create({ + metadata: { + ...createDefaultFileAttributes(), + name, + mime_type: mime, + Alt: alt, + Meta: meta, + FileKind: fileKind.id, + extension: (mime && mimeType.getExtension(mime)) ?? undefined, + }, + }); + + const file = internalFileService.toFile(fileMeta.id, fileMeta.metadata, fileKind, fileClient); + + internalFileService.writeAuditLog( + createAuditEvent({ + action: 'create', + message: `Created file "${file.name}" of kind "${file.fileKind}" and id "${file.id}"`, + }) + ); + + return file; + } +} diff --git a/x-pack/plugins/files/server/file/file_attributes_reducer.ts b/x-pack/plugins/files/server/file/file_attributes_reducer.ts new file mode 100644 index 00000000000000..93bf2f74545d97 --- /dev/null +++ b/x-pack/plugins/files/server/file/file_attributes_reducer.ts @@ -0,0 +1,72 @@ +/* + * 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 moment from 'moment'; +import { FileMetadata, UpdatableFileMetadata } from '../../common'; + +export type Action = + | { + action: 'delete'; + payload?: undefined; + } + | { + action: 'uploading'; + payload?: undefined; + } + | { action: 'uploaded'; payload: { size: number } } + | { action: 'uploadError'; payload?: undefined } + | { action: 'updateFile'; payload: Partial }; + +export function createDefaultFileAttributes(): Pick< + FileMetadata, + 'created' | 'Updated' | 'Status' +> { + const dateString = new Date().toISOString(); + return { + created: dateString, + Status: 'AWAITING_UPLOAD', + Updated: dateString, + }; +} + +export function fileAttributesReducer( + state: FileMetadata, + { action, payload }: Action +): FileMetadata { + switch (action) { + case 'delete': + return { ...state, Status: 'DELETED' }; + case 'uploading': + return { + ...state, + Status: 'UPLOADING', + Updated: moment().toISOString(), + }; + case 'uploaded': + return { + ...state, + ...payload, + Status: 'READY', + Updated: moment().toISOString(), + }; + case 'uploadError': + return { + ...state, + Status: 'UPLOAD_ERROR', + Updated: moment().toISOString(), + }; + case 'updateFile': + return { + ...state, + name: payload.name ?? state.name, + Alt: payload.alt ?? state.Alt, + Meta: payload.meta ?? state.Meta, + Updated: moment().toISOString(), + }; + default: + return state; + } +} diff --git a/x-pack/plugins/files/server/file/index.ts b/x-pack/plugins/files/server/file/index.ts new file mode 100644 index 00000000000000..02740d7eaab6d4 --- /dev/null +++ b/x-pack/plugins/files/server/file/index.ts @@ -0,0 +1,14 @@ +/* + * 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 * as fileErrors from './errors'; + +export { File } from './file'; +export { toJSON } from './to_json'; +export { createDefaultFileAttributes, fileAttributesReducer } from './file_attributes_reducer'; +export type { Action } from './file_attributes_reducer'; +export { fileErrors }; diff --git a/x-pack/plugins/files/server/file/to_json.ts b/x-pack/plugins/files/server/file/to_json.ts new file mode 100644 index 00000000000000..390aa1672e06ec --- /dev/null +++ b/x-pack/plugins/files/server/file/to_json.ts @@ -0,0 +1,36 @@ +/* + * 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 type { FileMetadata, FileJSON } from '../../common/types'; + +export function toJSON(id: string, attrs: FileMetadata): FileJSON { + const { + name, + mime_type: mimeType, + size, + created, + Updated, + FileKind, + Status, + Alt, + extension, + Meta, + } = attrs; + return { + id, + name, + mimeType, + size, + created, + extension, + alt: Alt, + status: Status, + meta: Meta as M, + updated: Updated, + fileKind: FileKind, + }; +} diff --git a/x-pack/plugins/files/server/file_client/create_es_file_client.ts b/x-pack/plugins/files/server/file_client/create_es_file_client.ts new file mode 100644 index 00000000000000..2ffb9bd458c6d3 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/create_es_file_client.ts @@ -0,0 +1,60 @@ +/* + * 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 type { Logger, ElasticsearchClient } from '@kbn/core/server'; +import { ElasticsearchBlobStorageClient } from '../blob_storage_service'; +import { FileClientImpl, FileClient } from './file_client'; +import { EsIndexFilesMetadataClient } from './file_metadata_client'; + +const NO_FILE_KIND = 'none'; + +/** + * Arguments to create an ES file client. + */ +export interface CreateEsFileClientArgs { + /** + * The name of the ES index that will store file metadata. + */ + metadataIndex: string; + /** + * The name of the ES index that will store file contents. + */ + blobStorageIndex: string; + /** + * An elasticsearch client that will be used to interact with the cluster + */ + elasticsearchClient: ElasticsearchClient; + /** + * The maximum file size to be write + */ + maxSizeBytes?: number; + /** + * A logger for debuggin purposes + */ + logger: Logger; +} + +/** + * A utility function for creating an instance of {@link FileClient} + * that will speak with ES indices only for file functionality. + * + * @note This client is not intended to be aware of {@link FileKind}s. + * + * @param arg - See {@link CreateEsFileClientArgs} + */ +export function createEsFileClient(arg: CreateEsFileClientArgs): FileClient { + const { blobStorageIndex, elasticsearchClient, logger, metadataIndex, maxSizeBytes } = arg; + return new FileClientImpl( + { + id: NO_FILE_KIND, + http: {}, + maxSizeBytes, + }, + new EsIndexFilesMetadataClient(metadataIndex, elasticsearchClient, logger), + new ElasticsearchBlobStorageClient(elasticsearchClient, blobStorageIndex, undefined, logger) + ); +} diff --git a/x-pack/plugins/files/server/file_client/file_client.ts b/x-pack/plugins/files/server/file_client/file_client.ts new file mode 100644 index 00000000000000..cc9a4a6de29946 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_client.ts @@ -0,0 +1,191 @@ +/* + * 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 { Readable } from 'stream'; +import cuid from 'cuid'; +import { FileKind, FileMetadata } from '../../common/types'; +import type { FileMetadataClient } from './file_metadata_client'; +import type { + BlobStorageClient, + UploadOptions as BlobUploadOptions, +} from '../blob_storage_service'; +import { enforceMaxByteSizeTransform } from './stream_transforms'; + +export interface DeleteArgs { + /** ID of the file to delete */ + id: string; + /** + * If `true`, the file will be deleted from the blob storage. + * + * @default true + */ + hasContent?: boolean; +} + +/** + * Args to create a file + */ +export interface CreateArgs { + /** + * Unique file ID + */ + id?: string; + /** + * The file's metadata + */ + metadata: Omit & { FileKind?: string }; +} + +export type UploadOptions = Omit; + +/** + * Wraps the {@link FileMetadataClient} and {@link BlobStorageClient} client + * to provide basic file CRUD functionality. + * + * For now this is just a shallow type of the implementation for export purposes. + */ +export interface FileClient { + /** See {@link FileMetadata.FileKind}. */ + fileKind: string; + + /** + * See {@link FileMetadataClient.create}. + * + * @param arg - Arg to create a file. + * */ + create(arg: CreateArgs): ReturnType; + + /** + * See {@link FileMetadataClient.get} + * + * @param arg - Argument to get a file + */ + get: FileMetadataClient['get']; + + /** + * {@link FileMetadataClient.update} + * + * @param arg - Argument to get a file + */ + update: FileMetadataClient['update']; + + /** + * Delete a file. + * @param arg - Argument to delete a file + */ + delete(arg: DeleteArgs): Promise; + + /** + * See {@link BlobStorageClient.delete} + * + * @param id - Argument to delete a file + */ + deleteContent: BlobStorageClient['delete']; + + /** + * See {@link FileMetadataClient.list} + * + * @param arg - Argument to list files + */ + list: FileMetadataClient['list']; + + /** + * See {@link FileMetadataClient.find}. + * + * @param arg - Argument to find files + */ + find: FileMetadataClient['find']; + + /** + * See {@link BlobStorageClient.upload} + * + * @param id - Readable stream to upload + * @param rs - Readable stream to upload + * @param opts - Argument for uploads + */ + upload(id: string, rs: Readable, opts?: UploadOptions): ReturnType; + + /** + * See {@link BlobStorageClient.download} + * + * @param args - to download a file + */ + download: BlobStorageClient['download']; +} +export class FileClientImpl implements FileClient { + constructor( + private fileKindDescriptor: FileKind, + private readonly metadataClient: FileMetadataClient, + private readonly blobStorageClient: BlobStorageClient + ) {} + + public get fileKind(): string { + return this.fileKindDescriptor.id; + } + + public create = async ({ + id, + metadata, + }: CreateArgs): ReturnType => { + return this.metadataClient.create({ + id: id || cuid(), + metadata: { + FileKind: this.fileKind, + ...metadata, + }, + }); + }; + + public get: FileMetadataClient['get'] = async (arg) => { + return this.metadataClient.get(arg); + }; + + public update: FileMetadataClient['update'] = (arg) => { + return this.metadataClient.update(arg); + }; + + public find: FileMetadataClient['find'] = (arg) => { + return this.metadataClient.find(arg); + }; + + public async delete({ id, hasContent = true }: DeleteArgs) { + if (hasContent) await this.blobStorageClient.delete(id); + return this.metadataClient.delete({ id }); + } + + public deleteContent: BlobStorageClient['delete'] = (arg) => { + return this.blobStorageClient.delete(arg); + }; + + public list: FileMetadataClient['list'] = (arg) => { + return this.metadataClient.list(arg); + }; + + /** + * Upload a blob + * @param id - The ID of the file content is associated with + * @param rs - The readable stream of the file content + * @param options - Options for the upload + */ + public upload = async ( + id: string, + rs: Readable, + options?: UploadOptions + ): ReturnType => { + return this.blobStorageClient.upload(rs, { + ...options, + transforms: [ + ...(options?.transforms || []), + enforceMaxByteSizeTransform(this.fileKindDescriptor.maxSizeBytes ?? Infinity), + ], + id, + }); + }; + + public download: BlobStorageClient['download'] = (args) => { + return this.blobStorageClient.download(args); + }; +} diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/es_index.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/es_index.ts new file mode 100644 index 00000000000000..5b41dca5e158e6 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/es_index.ts @@ -0,0 +1,149 @@ +/* + * 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 { once } from 'lodash'; +import { pipe } from 'lodash/fp'; +import { Logger } from '@kbn/core/server'; +import { toElasticsearchQuery } from '@kbn/es-query'; +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { MappingProperty } from '@elastic/elasticsearch/lib/api/types'; +import type { FilesMetrics, FileMetadata, Pagination } from '../../../../common'; +import type { FindFileArgs } from '../../../file_service'; +import type { + DeleteArg, + FileDescriptor, + FileMetadataClient, + GetArg, + GetUsageMetricsArgs, + ListArg, + UpdateArgs, +} from '../file_metadata_client'; +import { filterArgsToKuery, filterDeletedFiles } from './query_filters'; +import { fileObjectType } from '../../../saved_objects/file'; + +const filterArgsToESQuery = pipe(filterArgsToKuery, toElasticsearchQuery); + +const fileMappings: MappingProperty = { + dynamic: false, + type: 'object', + properties: { + ...fileObjectType.mappings.properties, + }, +}; + +interface FileDocument { + file: FileMetadata; +} + +export class EsIndexFilesMetadataClient implements FileMetadataClient { + constructor( + private readonly index: string, + private readonly esClient: ElasticsearchClient, + private readonly logger: Logger + ) {} + + private createIfNotExists = once(async () => { + try { + if (await this.esClient.indices.exists({ index: this.index })) { + return; + } + await this.esClient.indices.create({ + index: this.index, + mappings: { + dynamic: false, + properties: { + file: fileMappings, + }, + }, + }); + } catch (e) { + // best effort + } + }); + + async create({ id, metadata }: FileDescriptor): Promise> { + await this.createIfNotExists(); + const result = await this.esClient.index({ + index: this.index, + id, + document: { file: metadata }, + refresh: true, + }); + return { + id: result._id, + metadata, + }; + } + + async get({ id }: GetArg): Promise> { + const { _source: doc } = await this.esClient.get>({ + index: this.index, + id, + }); + + if (!doc) { + this.logger.error(`File with id "${id}" not found`); + throw new Error('File not found'); + } + + return { + id, + metadata: doc.file, + }; + } + + async delete({ id }: DeleteArg): Promise { + await this.esClient.delete({ index: this.index, id }); + } + + async update({ id, metadata }: UpdateArgs): Promise> { + await this.esClient.update({ index: this.index, id, doc: { file: metadata }, refresh: true }); + return this.get({ id }); + } + + private paginationToES({ page = 1, perPage = 50 }: Pagination) { + return { + size: perPage, + from: (page - 1) * perPage, + }; + } + + private attrPrefix: keyof FileDocument = 'file'; + + async list({ page, perPage }: ListArg = {}): Promise>> { + const result = await this.esClient.search>({ + index: this.index, + expand_wildcards: 'hidden', + query: toElasticsearchQuery(filterDeletedFiles({ attrPrefix: this.attrPrefix })), + ...this.paginationToES({ page, perPage }), + sort: 'file.created', + }); + + return result.hits.hits.map((hit) => { + return { + id: hit._id, + metadata: hit._source?.file!, + }; + }); + } + + async find({ page, perPage, ...filterArgs }: FindFileArgs): Promise>> { + const result = await this.esClient.search>({ + index: this.index, + expand_wildcards: 'hidden', + query: filterArgsToESQuery({ ...filterArgs, attrPrefix: this.attrPrefix }), + ...this.paginationToES({ page, perPage }), + sort: 'file.created', + }); + + return result.hits.hits.map((r) => ({ id: r._id, metadata: r._source?.file! })); + } + + async getUsageMetrics(arg: GetUsageMetricsArgs): Promise { + throw new Error('Not implemented'); + } +} diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/index.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/index.ts new file mode 100644 index 00000000000000..9e7273b685f89c --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { SavedObjectsFileMetadataClient } from './saved_objects'; +export { EsIndexFilesMetadataClient } from './es_index'; diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts new file mode 100644 index 00000000000000..4b33c60f320a45 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts @@ -0,0 +1,62 @@ +/* + * 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 { pipe, forEach } from 'lodash/fp'; +import { escapeKuery, KueryNode, nodeBuilder, nodeTypes } from '@kbn/es-query'; + +import { getFlattenedObject } from '@kbn/std'; + +import { FileMetadata, FileStatus } from '../../../../common/types'; +import { FindFileArgs } from '../../../file_service'; + +const { buildNode } = nodeTypes.function; + +const deletedStatus: FileStatus = 'DELETED'; + +export function filterDeletedFiles({ attrPrefix }: { attrPrefix: string }): KueryNode { + return buildNode('not', nodeBuilder.is(`${attrPrefix}.Status`, deletedStatus)); +} + +export function filterArgsToKuery({ + extension, + kind, + meta, + name, + status, + attrPrefix = '', +}: Omit & { attrPrefix?: string }): KueryNode { + const kueryExpressions: KueryNode[] = [filterDeletedFiles({ attrPrefix })]; + + const addFilters = (fieldName: keyof FileMetadata, values: string[] = []): void => { + if (values.length) { + const orExpressions = values + .filter(Boolean) + .map((value) => nodeBuilder.is(`${attrPrefix}.${fieldName}`, escapeKuery(value))); + kueryExpressions.push(nodeBuilder.or(orExpressions)); + } + }; + + addFilters('name', name); + addFilters('FileKind', kind); + addFilters('Status', status); + addFilters('extension', extension); + + if (meta) { + const addMetaFilters = pipe( + getFlattenedObject, + Object.entries, + forEach(([fieldName, value]) => { + addFilters( + `Meta.${fieldName}` as keyof FileMetadata, + Array.isArray(value) ? value : [value] + ); + }) + ); + addMetaFilters(meta); + } + + return nodeBuilder.and(kueryExpressions); +} diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts new file mode 100644 index 00000000000000..9afd12689acbf7 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/adapters/saved_objects.ts @@ -0,0 +1,160 @@ +/* + * 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 { reduce } from 'lodash'; +import type { Logger } from '@kbn/core/server'; +import type { + SavedObjectsClientContract, + ISavedObjectsRepository, + SavedObjectsOpenPointInTimeResponse, +} from '@kbn/core-saved-objects-api-server'; +import { AggregationsSumAggregate } from '@elastic/elasticsearch/lib/api/types'; +import { escapeKuery } from '@kbn/es-query'; + +import { FindFileArgs } from '../../../file_service/file_action_types'; +import { ES_FIXED_SIZE_INDEX_BLOB_STORE } from '../../../../common/constants'; +import type { FileMetadata, FilesMetrics, FileStatus, Pagination } from '../../../../common/types'; +import type { + FileMetadataClient, + UpdateArgs, + FileDescriptor, + GetUsageMetricsArgs, +} from '../file_metadata_client'; + +import { filterArgsToKuery } from './query_filters'; + +interface TermsAgg { + buckets: Array<{ key: string; doc_count: number }>; +} +interface FilesMetricsAggs { + bytesUsed: AggregationsSumAggregate; + status: TermsAgg; + extension: TermsAgg; +} + +export class SavedObjectsFileMetadataClient implements FileMetadataClient { + constructor( + private readonly soType: string, + private readonly soClient: SavedObjectsClientContract | ISavedObjectsRepository, + private readonly logger: Logger + ) {} + + async create({ id, metadata }: FileDescriptor): Promise { + const result = await this.soClient.create(this.soType, metadata, { id }); + return { id: result.id, metadata: result.attributes }; + } + async update({ id, metadata }: UpdateArgs): Promise { + const result = await this.soClient.update(this.soType, id, metadata); + return { + id: result.id, + metadata: result.attributes as FileDescriptor['metadata'], + }; + } + async get({ id }: { id: string }): Promise { + const result = await this.soClient.get(this.soType, id); + return { + id: result.id, + metadata: result.attributes as FileDescriptor['metadata'], + }; + } + async list({ fileKind, page, perPage }: { fileKind?: string } & Pagination = {}): Promise< + FileDescriptor[] + > { + let filter = `NOT ${this.soType}.attributes.Status: DELETED`; + if (fileKind) { + filter = `${this.soType}.attributes.FileKind: ${escapeKuery(fileKind)} AND ${filter}`; + } + const result = await this.soClient.find({ + type: this.soType, + filter, + page, + perPage, + }); + return result.saved_objects.map((file) => ({ + id: file.id, + metadata: file.attributes as FileDescriptor['metadata'], + })); + } + + async find({ page, perPage, ...filterArgs }: FindFileArgs): Promise { + const result = await this.soClient.find({ + type: this.soType, + filter: filterArgsToKuery({ ...filterArgs, attrPrefix: `${this.soType}.attributes` }), + page, + perPage, + sortOrder: 'desc', + sortField: 'created', + }); + return result.saved_objects.map((so) => ({ + id: so.id, + metadata: so.attributes as FileMetadata, + })); + } + + async delete({ id }: { id: string }): Promise { + await this.soClient.delete(this.soType, id); + } + + async getUsageMetrics({ + esFixedSizeIndex: { capacity }, + }: GetUsageMetricsArgs): Promise { + let pit: undefined | SavedObjectsOpenPointInTimeResponse; + try { + pit = await this.soClient.openPointInTimeForType(this.soType); + const { aggregations } = await this.soClient.find({ + type: this.soType, + pit, + aggs: { + bytesUsed: { + sum: { + field: `${this.soType}.attributes.size`, + }, + }, + status: { + terms: { + field: `${this.soType}.attributes.Status`, + }, + }, + extension: { + terms: { + field: `${this.soType}.attributes.extension`, + }, + }, + }, + }); + + if (aggregations) { + const used = aggregations.bytesUsed!.value!; + return { + storage: { + [ES_FIXED_SIZE_INDEX_BLOB_STORE]: { + capacity, + available: capacity - used, + used, + }, + }, + countByExtension: reduce( + aggregations.extension.buckets, + (acc, { key, doc_count: docCount }) => ({ ...acc, [key]: docCount }), + {} + ), + countByStatus: reduce( + aggregations.status.buckets, + (acc, { key, doc_count: docCount }) => ({ ...acc, [key]: docCount }), + {} as Record + ), + }; + } + + throw new Error('Could not retrieve usage metrics'); + } finally { + if (pit) { + await this.soClient.closePointInTime(pit.id).catch(this.logger.error.bind(this.logger)); + } + } + } +} diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts new file mode 100644 index 00000000000000..5934ac1f422b85 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts @@ -0,0 +1,137 @@ +/* + * 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 { ES_FIXED_SIZE_INDEX_BLOB_STORE } from '../../../common/constants'; +import type { FileMetadata, FilesMetrics, Pagination } from '../../../common/types'; +import type { FindFileArgs } from '../../file_service/file_action_types'; + +/** + * Args to get usage metrics + */ +export interface GetUsageMetricsArgs { + /** + * The ES backed fixed size storage + */ + [ES_FIXED_SIZE_INDEX_BLOB_STORE]: { + /** + * Use this number to calculate free space when calculating metrics + */ + capacity: number; + }; +} + +/** + * Meta description of a file. + */ +export interface FileDescriptor { + /** + * Unique ID of a file, used to locate a file. + */ + id: string; + /** + * The file's metadata. + */ + metadata: FileMetadata; +} + +/** + * Update a file args + */ +export interface UpdateArgs { + /** + * A unique file ID. + */ + id: string; + /** + * The file's metadata. + */ + metadata: Partial>; +} + +/** + * Get a file + */ +export interface GetArg { + /** + * Unique ID of file metadata + */ + id: string; +} + +export interface DeleteArg { + /** + * Unique ID of file metadata to delete + * + * @note Deleting file metadata should only be done once all other related + * file objects have been deleted + */ + id: string; +} + +export interface ListArg extends Pagination { + /** + * The file kind to scope this query to + */ + fileKind?: string; +} + +export interface FindArg extends Pagination { + /** + * The file kind to scope this query to + */ + fileKind?: string; +} + +/** + * An abstraction of storage implementation of file object's (i.e., metadata) + */ +export interface FileMetadataClient { + /** + * Create an instance of file metadata + * + * @param arg - Provide an ID and metadata + */ + create(arg: FileDescriptor): Promise; + + /** + * Get file metadata + * + * @param arg - Arguments to retrieve file metadata + */ + get(arg: GetArg): Promise; + + /** + * The file metadata to update + * + * @param arg - Arguments to update file metadata + */ + update(arg: UpdateArgs): Promise; + /** + * Delete an instance of file metadata + * + * @param arg - Arguments to delete file metadata + */ + delete(arg: DeleteArg): Promise; + /** + * List all instances of metadata for a file kind. + * + * @param arg - Arguments to list file metadata + */ + list(arg?: ListArg): Promise; + /** + * Search for a set of file kind instances that match the filters. + * + * @param arg - Filters and other settings to match against + */ + find(arg: FindFileArgs): Promise; + /** + * Prepare a set of metrics based on the file metadata. + * + * @param arg - Argument to get usage metrics + */ + getUsageMetrics(arg: GetUsageMetricsArgs): Promise; +} diff --git a/x-pack/plugins/files/server/file_client/file_metadata_client/index.ts b/x-pack/plugins/files/server/file_client/file_metadata_client/index.ts new file mode 100644 index 00000000000000..e4b84a1c6cb04a --- /dev/null +++ b/x-pack/plugins/files/server/file_client/file_metadata_client/index.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. + */ + +export type { + FileMetadataClient, + FileDescriptor, + DeleteArg as DeleteMetedataArg, + FindArg as FindMetadataArg, + GetArg as GetMetadataArg, + GetUsageMetricsArgs, + ListArg as ListMetadataArg, + UpdateArgs as UpdateMetadataArg, +} from './file_metadata_client'; +export { SavedObjectsFileMetadataClient, EsIndexFilesMetadataClient } from './adapters'; diff --git a/x-pack/plugins/files/server/file_client/index.ts b/x-pack/plugins/files/server/file_client/index.ts new file mode 100644 index 00000000000000..2f764a53224e4d --- /dev/null +++ b/x-pack/plugins/files/server/file_client/index.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export { EsIndexFilesMetadataClient, SavedObjectsFileMetadataClient } from './file_metadata_client'; +export type { + FileMetadataClient, + DeleteMetedataArg, + FileDescriptor, + FindMetadataArg, + GetMetadataArg, + GetUsageMetricsArgs, + ListMetadataArg, + UpdateMetadataArg, +} from './file_metadata_client'; +export { FileClientImpl } from './file_client'; +export type { FileClient } from './file_client'; +export { createEsFileClient } from './create_es_file_client'; +export type { CreateEsFileClientArgs } from './create_es_file_client'; diff --git a/x-pack/plugins/files/server/file_client/integration_tests/es_file_client.test.ts b/x-pack/plugins/files/server/file_client/integration_tests/es_file_client.test.ts new file mode 100644 index 00000000000000..3ab200533c6dad --- /dev/null +++ b/x-pack/plugins/files/server/file_client/integration_tests/es_file_client.test.ts @@ -0,0 +1,217 @@ +/* + * 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 { Readable } from 'stream'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { TestEnvironmentUtils, setupIntegrationEnvironment } from '../../test_utils'; +import { createEsFileClient } from '../create_es_file_client'; +import { FileClient } from '../file_client'; + +/** + * This file client is using Elasticsearch interfaces directly to manage files. + */ +describe('ES-index-backed file client', () => { + let esClient: TestEnvironmentUtils['esClient']; + let fileClient: FileClient; + let testHarness: TestEnvironmentUtils; + + beforeAll(async () => { + testHarness = await setupIntegrationEnvironment(); + ({ esClient } = testHarness); + }); + + beforeEach(() => { + fileClient = createEsFileClient({ + blobStorageIndex: '.kibana-test-blob', + metadataIndex: '.kibana-test-metadata', + elasticsearchClient: esClient, + logger: loggingSystemMock.create().get(), + }); + }); + + afterAll(async () => { + await testHarness.cleanupAfterAll(); + }); + + test('create a new file', async () => { + const file = await fileClient.create({ + id: '123', + metadata: { + Status: 'AWAITING_UPLOAD', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name', + }, + }); + expect(file).toEqual( + expect.objectContaining({ + id: '123', + metadata: { + FileKind: 'none', + Status: 'AWAITING_UPLOAD', + Updated: expect.any(String), + created: expect.any(String), + name: 'cool name', + }, + }) + ); + await fileClient.delete({ id: file.id, hasContent: false }); + }); + + test('uploads and downloads file content', async () => { + let { id, metadata } = await fileClient.create({ + id: '123', + metadata: { + Status: 'AWAITING_UPLOAD', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name', + }, + }); + + const { size } = await fileClient.upload(id, Readable.from([Buffer.from('test')])); + ({ id, metadata } = await fileClient.update({ + id, + metadata: { ...metadata, size, Status: 'READY' }, + })); + + const file = await fileClient.get({ id }); + const rs = await fileClient.download({ id: file.id, size: file.metadata.size }); + const chunks: Buffer[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(Buffer.concat(chunks).toString('utf-8')).toBe('test'); + + await fileClient.delete({ id, hasContent: true }); + }); + + test('searches across files', async () => { + const { id: id1 } = await fileClient.create({ + id: '123', + metadata: { + Status: 'AWAITING_UPLOAD', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name 1', + Meta: { + test: '1', + }, + }, + }); + const { id: id2 } = await fileClient.create({ + id: '1234', + metadata: { + Status: 'UPLOADING', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name 2', + Meta: { + test: '2', + }, + }, + }); + const { id: id3 } = await fileClient.create({ + id: '12345', + metadata: { + Status: 'READY', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name 3', + Meta: { + test: '3', + }, + }, + }); + + { + const results = await fileClient.find({ + status: ['READY'], + meta: { test: '3' }, + }); + + expect(results).toHaveLength(1); + + expect(results[0]).toEqual( + expect.objectContaining({ + id: id3, + }) + ); + } + + { + const results = await fileClient.find({ + status: ['READY', 'AWAITING_UPLOAD'], + }); + + expect(results).toHaveLength(2); + + expect(results[0]).toEqual( + expect.objectContaining({ + id: id1, + }) + ); + + expect(results[1]).toEqual( + expect.objectContaining({ + id: id3, + }) + ); + } + + await Promise.all([ + fileClient.delete({ id: id1 }), + fileClient.delete({ id: id2 }), + fileClient.delete({ id: id3 }), + ]); + }); + + test('does not list deleted files', async () => { + const { id: id1 } = await fileClient.create({ + id: '123', + metadata: { + Status: 'AWAITING_UPLOAD', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name 1', + Meta: { + test: '1', + }, + }, + }); + const { id: id2 } = await fileClient.create({ + id: '1234', + metadata: { + Status: 'DELETED', + created: new Date().toISOString(), + Updated: new Date().toISOString(), + name: 'cool name 2', + Meta: { + test: '2', + }, + }, + }); + + const list = await fileClient.list(); + + expect(list).toHaveLength(1); + expect(list[0]).toEqual( + expect.objectContaining({ + id: '123', + metadata: { + FileKind: 'none', + Meta: { test: '1' }, + Status: 'AWAITING_UPLOAD', + Updated: expect.any(String), + created: expect.any(String), + name: 'cool name 1', + }, + }) + ); + + await Promise.all([fileClient.delete({ id: id1 }), fileClient.delete({ id: id2 })]); + }); +}); diff --git a/x-pack/plugins/files/server/file_client/stream_transforms/index.ts b/x-pack/plugins/files/server/file_client/stream_transforms/index.ts new file mode 100644 index 00000000000000..b3a82e897a02cb --- /dev/null +++ b/x-pack/plugins/files/server/file_client/stream_transforms/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { enforceMaxByteSizeTransform } from './max_byte_size_transform'; diff --git a/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/errors.ts b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/errors.ts new file mode 100644 index 00000000000000..3b2c236e8a2870 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/errors.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export class MaxByteSizeExceededError extends Error { + constructor(expectedSize: number) { + super(`Maximum of ${expectedSize} bytes exceeded`); + Error.captureStackTrace(this); + } +} diff --git a/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/index.ts b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/index.ts new file mode 100644 index 00000000000000..b3a82e897a02cb --- /dev/null +++ b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { enforceMaxByteSizeTransform } from './max_byte_size_transform'; diff --git a/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.test.ts b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.test.ts new file mode 100644 index 00000000000000..9697624edb4714 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.test.ts @@ -0,0 +1,40 @@ +/* + * 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 { Readable, Writable, pipeline } from 'stream'; +import { promisify } from 'util'; +import { enforceMaxByteSizeTransform } from './max_byte_size_transform'; + +const pipe = promisify(pipeline); + +class DummyWrite extends Writable { + public chunks: string[] = []; + _write(chunk: any, encoding: BufferEncoding, cb: (error?: Error | null) => void): void { + this.chunks.push(chunk.toString()); + cb(null); + } +} + +describe('Max byte size transform', () => { + it('should allow data to stream through it', async () => { + const data = 'abc'.repeat(10); + const dataStream = [data, data, data]; + const src = Readable.from(dataStream); + const dest = new DummyWrite(); + await pipe(src, enforceMaxByteSizeTransform(Infinity), dest); + expect(dest.chunks.join('')).toEqual(dataStream.join('')); + }); + it('should throw an error when the max number of bytes has been reached', async () => { + const data = 'abc'.repeat(10); + const dataStream = [data, data, data]; + const src = Readable.from(dataStream); + const dest = new DummyWrite(); + await expect(() => pipe(src, enforceMaxByteSizeTransform(5), dest)).rejects.toThrowError( + new Error('Maximum of 5 bytes exceeded') + ); + }); +}); diff --git a/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.ts b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.ts new file mode 100644 index 00000000000000..c2634bcbf8fe29 --- /dev/null +++ b/x-pack/plugins/files/server/file_client/stream_transforms/max_byte_size_transform/max_byte_size_transform.ts @@ -0,0 +1,26 @@ +/* + * 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 { Transform } from 'stream'; +import { MaxByteSizeExceededError } from './errors'; + +export function enforceMaxByteSizeTransform(maxByteSize: number) { + let bytesSeen: number = 0; + return new Transform({ + transform(chunk: Buffer, _, cb) { + if (!Buffer.isBuffer(chunk)) + throw new Error(`Received a non-buffer chunk. All chunk must be buffers.`); + + bytesSeen += chunk.byteLength; + if (bytesSeen > maxByteSize) { + cb(new MaxByteSizeExceededError(maxByteSize)); + } else { + cb(null, chunk); + } + }, + }); +} diff --git a/x-pack/plugins/files/server/file_kinds_registry/index.ts b/x-pack/plugins/files/server/file_kinds_registry/index.ts new file mode 100644 index 00000000000000..bd550e43dc4b7c --- /dev/null +++ b/x-pack/plugins/files/server/file_kinds_registry/index.ts @@ -0,0 +1,66 @@ +/* + * 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 { createGetterSetter } from '@kbn/kibana-utils-plugin/common'; +import assert from 'assert'; +import { FileKind } from '../../common'; + +import { registerFileKindRoutes } from '../routes/file_kind'; +import { FilesRouter } from '../routes/types'; + +export interface FileKindsRegistry { + /** + * Register a new file kind. + */ + register(fileKind: FileKind): void; + + /** + * Gets a {@link FileKind} or throws. + */ + get(id: string): FileKind; + + /** + * Return all registered {@link FileKind}s. + */ + getAll(): FileKind[]; +} + +/** + * @internal + */ +export class FileKindsRegistryImpl implements FileKindsRegistry { + constructor(private readonly router: FilesRouter) {} + + private readonly fileKinds = new Map(); + + register(fileKind: FileKind) { + if (this.fileKinds.get(fileKind.id)) { + throw new Error(`File kind "${fileKind.id}" already registered.`); + } + + if (fileKind.id !== encodeURIComponent(fileKind.id)) { + throw new Error( + `File kind id "${fileKind.id}" is not a valid file kind ID. Choose an ID that does not need to be URI encoded.` + ); + } + + this.fileKinds.set(fileKind.id, fileKind); + registerFileKindRoutes(this.router, fileKind); + } + + get(id: string): FileKind { + const fileKind = this.fileKinds.get(id); + assert(fileKind, `File kind with id "${id}" not found.`); + return fileKind; + } + + getAll(): FileKind[] { + return Array.from(this.fileKinds.values()); + } +} + +export const [getFileKindsRegistry, setFileKindsRegistry] = + createGetterSetter('fileKindsRegistry'); diff --git a/x-pack/plugins/files/server/file_service/errors.ts b/x-pack/plugins/files/server/file_service/errors.ts new file mode 100644 index 00000000000000..905f26cf8fe142 --- /dev/null +++ b/x-pack/plugins/files/server/file_service/errors.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export class FileNotFoundError extends Error { + constructor(message: string) { + super(message); + Error.captureStackTrace(this); + } +} diff --git a/x-pack/plugins/files/server/file_service/file_action_types.ts b/x-pack/plugins/files/server/file_service/file_action_types.ts new file mode 100644 index 00000000000000..c3d3a67ec6c66e --- /dev/null +++ b/x-pack/plugins/files/server/file_service/file_action_types.ts @@ -0,0 +1,118 @@ +/* + * 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 type { Pagination, UpdatableFileMetadata } from '../../common/types'; + +/** + * Arguments to create a new file. + */ +export interface CreateFileArgs { + /** + * File name + */ + name: string; + /** + * File kind, must correspond to a registered {@link FileKind}. + */ + fileKind: string; + /** + * Alternate text for accessibility and display purposes. + */ + alt?: string; + /** + * Custom metadata like tags or identifiers for the file. + */ + meta?: Meta; + /** + * The MIME type of the file. + */ + mime?: string; +} + +/** + * Arguments to update a file + */ +export interface UpdateFileArgs { + /** + * File ID. + */ + id: string; + /** + * File kind, must correspond to a registered {@link FileKind}. + */ + fileKind: string; + /** + * Attributes to update. + */ + attributes: UpdatableFileMetadata; +} + +/** + * Arguments to delete a file. + */ +export interface DeleteFileArgs { + /** + * File ID. + */ + id: string; + /** + * File kind, must correspond to a registered {@link FileKind}. + */ + fileKind: string; +} + +/** + * Arguments list files. + */ +export interface ListFilesArgs extends Pagination { + /** + * File kind, must correspond to a registered {@link FileKind}. + */ + fileKind: string; +} + +/** + * Arguments to get a file by ID. + */ +export interface GetByIdArgs { + /** + * File ID. + */ + id: string; + /** + * File kind, must correspond to a registered {@link FileKind}. + */ + fileKind: string; +} + +/** + * Arguments to filter for files. + * + * @note Individual values in a filter are "OR"ed together filters are "AND"ed together. + */ +export interface FindFileArgs extends Pagination { + /** + * File kind(s), see {@link FileKind}. + */ + kind?: string[]; + /** + * File name(s). + */ + name?: string[]; + /** + * File extension(s). + */ + extension?: string[]; + /** + * File status(es). + */ + status?: string[]; + /** + * File metadata values. These values are governed by the consumer. + */ + meta?: Record; +} diff --git a/x-pack/plugins/files/server/file_service/file_service.ts b/x-pack/plugins/files/server/file_service/file_service.ts new file mode 100644 index 00000000000000..90303ac715437d --- /dev/null +++ b/x-pack/plugins/files/server/file_service/file_service.ts @@ -0,0 +1,108 @@ +/* + * 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 type { File, FileJSON, FilesMetrics } from '../../common'; +import type { FileShareServiceStart } from '../file_share_service/types'; +import type { + CreateFileArgs, + UpdateFileArgs, + DeleteFileArgs, + GetByIdArgs, + ListFilesArgs, + FindFileArgs, +} from './file_action_types'; + +/** + * Public file service interface. + */ +export interface FileServiceStart { + /** + * Create a new file. + * + * Once created, the file content can be uploaded. See {@link File}. + * + * @param args - create file arg + */ + create(args: CreateFileArgs): Promise>; + + /** + * Update updatable file attributes like name and meta. + * + * @param args - update file args + */ + update(args: UpdateFileArgs): Promise>; + + /** + * Delete a file. + * + * @param args - delete file args + */ + delete(args: DeleteFileArgs): Promise; + + /** + * Get a file by ID. Will throw if file cannot be found. + * + * @param args - get file by ID args + */ + getById(args: GetByIdArgs): Promise>; + + /** + * Find files given a set of parameters. + * + * @param args - find files args + */ + find(args: FindFileArgs): Promise>>; + + /** + * List all files of specific file kind. + * + * @param args - list files args + */ + list(args: ListFilesArgs): Promise>>; + + /** + * Get an instance of a share object + * + * @param arg - get share args + */ + getShareObject: FileShareServiceStart['get']; + + /** + * List share objects + * + * @param arg - list share objects args + */ + listShareObjects: FileShareServiceStart['list']; + + /** + * Update an instance of a share object + * + * @param args - update share args + */ + updateShareObject: FileShareServiceStart['update']; + + /** + * Delete a share instance + * + * @param args - delete share args + */ + deleteShareObject: FileShareServiceStart['delete']; + + /** + * Get the current usage metrics for all storage media. + * + * Returns diagnostics or `undefined` if metrics could not be retrieved. + */ + getUsageMetrics(): Promise; + + /** + * Get a file by a secret token. + * + * @param token - secret token + */ + getByToken(token: string): Promise>; +} diff --git a/x-pack/plugins/files/server/file_service/file_service_factory.ts b/x-pack/plugins/files/server/file_service/file_service_factory.ts new file mode 100644 index 00000000000000..bed007b00e5071 --- /dev/null +++ b/x-pack/plugins/files/server/file_service/file_service_factory.ts @@ -0,0 +1,140 @@ +/* + * 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 { + SavedObjectsServiceSetup, + SavedObjectsServiceStart, + Logger, + KibanaRequest, +} from '@kbn/core/server'; +import { SecurityPluginSetup } from '@kbn/security-plugin/server'; + +import type { File, FileJSON, FileMetadata } from '../../common'; +import { fileObjectType, fileShareObjectType } from '../saved_objects'; +import { BlobStorageService } from '../blob_storage_service'; +import { InternalFileShareService } from '../file_share_service'; +import { + CreateFileArgs, + FindFileArgs, + GetByIdArgs, + ListFilesArgs, + UpdateFileArgs, +} from './file_action_types'; +import { InternalFileService } from './internal_file_service'; +import { FileServiceStart } from './file_service'; +import { FileKindsRegistry } from '../file_kinds_registry'; +import { SavedObjectsFileMetadataClient } from '../file_client'; + +/** + * A simple interface for getting an instance of {@link FileServiceStart} + */ +export interface FileServiceFactory { + /** + * Get a file service instance that is scoped to the current user request. + * + * @param req - the Kibana request to scope the service to + */ + asScoped(req: KibanaRequest): FileServiceStart; + + /** + * Get a file service instance that is scoped to the internal user. + * + * @note + * Do not use this to drive interactions with files that are initiated by a + * user. + */ + asInternal(): FileServiceStart; +} + +/** + * Factory for creating {@link FileServiceStart} instances. + */ +export class FileServiceFactoryImpl implements FileServiceFactory { + constructor( + private readonly savedObjectsService: SavedObjectsServiceStart, + private readonly blobStorageService: BlobStorageService, + private readonly security: undefined | SecurityPluginSetup, + private readonly fileKindRegistry: FileKindsRegistry, + private readonly logger: Logger + ) {} + + private createFileService(req?: KibanaRequest): FileServiceStart { + const hiddenTypes = [fileObjectType.name, fileShareObjectType.name]; + const soClient = req + ? this.savedObjectsService.getScopedClient(req, { + includedHiddenTypes: hiddenTypes, + }) + : this.savedObjectsService.createInternalRepository(hiddenTypes); + + const auditLogger = req + ? this.security?.audit.asScoped(req) + : this.security?.audit.withoutRequest; + + const internalFileShareService = new InternalFileShareService(soClient); + const soMetadataClient = new SavedObjectsFileMetadataClient( + fileObjectType.name, + soClient, + this.logger.get('so-metadata-client') + ); + + const internalFileService = new InternalFileService( + soMetadataClient, + this.blobStorageService, + internalFileShareService, + auditLogger, + this.fileKindRegistry, + this.logger + ); + + return { + async create(args: CreateFileArgs) { + return internalFileService.createFile(args) as Promise>; + }, + async update(args: UpdateFileArgs) { + return internalFileService.updateFile(args) as Promise>; + }, + async delete(args) { + return internalFileService.deleteFile(args); + }, + async getById(args: GetByIdArgs) { + return internalFileService.getById(args) as Promise>; + }, + async find(args: FindFileArgs) { + return internalFileService.findFilesJSON(args) as Promise>>; + }, + async list(args: ListFilesArgs) { + return internalFileService.list(args) as Promise>>; + }, + async getUsageMetrics() { + return internalFileService.getUsageMetrics(); + }, + async getByToken(token: string) { + return internalFileService.getByToken(token) as Promise>; + }, + getShareObject: internalFileShareService.get.bind(internalFileShareService), + updateShareObject: internalFileShareService.update.bind(internalFileShareService), + deleteShareObject: internalFileShareService.delete.bind(internalFileShareService), + listShareObjects: internalFileShareService.list.bind(internalFileShareService), + }; + } + + public asScoped(req: KibanaRequest): FileServiceStart { + return this.createFileService(req); + } + + public asInternal(): FileServiceStart { + return this.createFileService(); + } + + /** + * This function can only called during Kibana's setup phase + */ + public static setup(savedObjectsSetup: SavedObjectsServiceSetup): void { + savedObjectsSetup.registerType>(fileObjectType); + savedObjectsSetup.registerType(fileShareObjectType); + } +} diff --git a/x-pack/plugins/files/server/file_service/index.ts b/x-pack/plugins/files/server/file_service/index.ts new file mode 100644 index 00000000000000..c094c9f2d056b1 --- /dev/null +++ b/x-pack/plugins/files/server/file_service/index.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. + */ + +export { FileServiceFactoryImpl as FileServiceFactory } from './file_service_factory'; +export type { + CreateFileArgs, + DeleteFileArgs, + FindFileArgs, + GetByIdArgs, + ListFilesArgs, + UpdateFileArgs, +} from './file_action_types'; +export type { FileServiceStart } from './file_service'; +export * as errors from './errors'; diff --git a/x-pack/plugins/files/server/file_service/internal_file_service.ts b/x-pack/plugins/files/server/file_service/internal_file_service.ts new file mode 100644 index 00000000000000..567df3e1378485 --- /dev/null +++ b/x-pack/plugins/files/server/file_service/internal_file_service.ts @@ -0,0 +1,156 @@ +/* + * 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 { Logger, SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { AuditEvent, AuditLogger } from '@kbn/security-plugin/server'; + +import { BlobStorageService } from '../blob_storage_service'; +import { InternalFileShareService } from '../file_share_service'; +import { FileMetadata, File as IFile, FileKind, FileJSON, FilesMetrics } from '../../common'; +import { File, toJSON } from '../file'; +import { FileKindsRegistry } from '../file_kinds_registry'; +import { FileNotFoundError } from './errors'; +import type { FileMetadataClient } from '../file_client'; +import type { + CreateFileArgs, + UpdateFileArgs, + DeleteFileArgs, + FindFileArgs, + GetByIdArgs, + ListFilesArgs, +} from './file_action_types'; +import { FileClientImpl } from '../file_client/file_client'; +/** + * Service containing methods for working with files. + * + * All file business logic is encapsulated in the {@link File} class. + * + * @internal + */ +export class InternalFileService { + constructor( + private readonly metadataClient: FileMetadataClient, + private readonly blobStorageService: BlobStorageService, + private readonly fileShareService: InternalFileShareService, + private readonly auditLogger: undefined | AuditLogger, + private readonly fileKindRegistry: FileKindsRegistry, + private readonly logger: Logger + ) {} + + public async createFile(args: CreateFileArgs): Promise { + const fileKind = this.getFileKind(args.fileKind); + return await File.create( + { ...args, fileKind }, + this, + new FileClientImpl( + fileKind, + this.metadataClient, + this.blobStorageService.createBlobStorageClient(fileKind.blobStoreSettings) + ) + ); + } + + public writeAuditLog(event: AuditEvent) { + if (this.auditLogger) { + this.auditLogger.log(event); + } else { + // Otherwise just log to info + this.logger.info(event.message); + } + } + + public async updateFile({ attributes, fileKind, id }: UpdateFileArgs): Promise { + const file = await this.getById({ fileKind, id }); + return await file.update(attributes); + } + + public async deleteFile({ id, fileKind }: DeleteFileArgs): Promise { + const file = await this.getById({ id, fileKind }); + await file.delete(); + } + + private async get(id: string) { + try { + const { metadata } = await this.metadataClient.get({ id }); + if (metadata.Status === 'DELETED') { + throw new FileNotFoundError('File has been deleted'); + } + return this.toFile(id, metadata, this.getFileKind(metadata.FileKind)); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + throw new FileNotFoundError('File not found'); + } + this.logger.error(`Could not retrieve file: ${e}`); + throw e; + } + } + + public async getById({ fileKind, id }: GetByIdArgs): Promise { + const file = await this.get(id); + if (file.fileKind !== fileKind) { + throw new Error(`Unexpected file kind "${file.fileKind}", expected "${fileKind}".`); + } + return file; + } + + public async list({ + fileKind: fileKindId, + page = 1, + perPage = 100, + }: ListFilesArgs): Promise { + const fileKind = this.getFileKind(fileKindId); + const result = await this.metadataClient.list({ + fileKind: fileKind.id, + page, + perPage, + }); + return result.map((file) => this.toFile(file.id, file.metadata, fileKind)); + } + + public toFile( + id: string, + fileMetadata: FileMetadata, + fileKind: FileKind, + fileClient?: FileClientImpl + ): IFile { + return new File( + id, + fileMetadata, + fileClient ?? + new FileClientImpl( + fileKind, + this.metadataClient, + this.blobStorageService.createBlobStorageClient(fileKind.blobStoreSettings) + ), + this, + this.fileShareService, + this.logger.get(`file-${id}`) + ); + } + + public getFileKind(id: string): FileKind { + return this.fileKindRegistry.get(id); + } + + public async findFilesJSON(args: FindFileArgs): Promise { + const result = await this.metadataClient.find(args); + return result.map((r) => toJSON(r.id, r.metadata)); + } + + public async getUsageMetrics(): Promise { + return this.metadataClient.getUsageMetrics({ + esFixedSizeIndex: { + capacity: this.blobStorageService.getStaticBlobStorageSettings().esFixedSizeIndex.capacity, + }, + }); + } + + public async getByToken(token: string) { + const { fileId } = await this.fileShareService.getByToken(token); + return this.get(fileId); + } +} diff --git a/x-pack/plugins/files/server/file_share_service/errors.ts b/x-pack/plugins/files/server/file_share_service/errors.ts new file mode 100644 index 00000000000000..89979f06899797 --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/errors.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +/* eslint-disable max-classes-per-file */ + +abstract class FileShareError extends Error { + constructor(message: string) { + super(message); + Error.captureStackTrace(this); + } +} + +export class ExpiryDateInThePastError extends FileShareError {} +export class FileShareNotFoundError extends FileShareError {} +export class FileShareTokenInvalidError extends FileShareError {} diff --git a/x-pack/plugins/files/server/file_share_service/generate_share_token.test.ts b/x-pack/plugins/files/server/file_share_service/generate_share_token.test.ts new file mode 100644 index 00000000000000..93767c74849860 --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/generate_share_token.test.ts @@ -0,0 +1,16 @@ +/* + * 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 { generateShareToken } from './generate_share_token'; + +describe('generateShareToken', () => { + it('should contain only expected chars of a given length', () => { + for (let i = 0; i < 50; i++) { + expect(generateShareToken()).toMatch(/^[a-zA-O0-9]{40}$/); + } + }); +}); diff --git a/x-pack/plugins/files/server/file_share_service/generate_share_token.ts b/x-pack/plugins/files/server/file_share_service/generate_share_token.ts new file mode 100644 index 00000000000000..ef779db49223a7 --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/generate_share_token.ts @@ -0,0 +1,31 @@ +/* + * 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 crypto from 'crypto'; + +/** + * Char set of 51 characters gets an even distribution for each byte of randomness + * generated because 255 (max number) % 51 = 0. + */ +const CHAR_SET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO0123456789'; + +/** + * Generate 40 random characters of a pre-checked charset for share tokens. + * + * Samples: + * + * a7EyHf1LrK37uCx4ld3m7Lhkgl2kxuMrIn6umkjz + * 72wq34jHgkix9noCbEKIjfmivD1pBypxmbs3wzEn + * mtr9Eq5w06rIhDHzM73vBumL4joKjkaILK9a5ikI + * 6cbikArFgx1gwjcBc9v3FxdGojzjdpKbCGJspCHA + * sOi94wwygidgKozwfDnoeIhpFywMwyMkBFcd5oCi + */ +export function generateShareToken(): string { + return [...crypto.randomBytes(40)].reduce((acc, nr) => { + return acc + CHAR_SET[nr % CHAR_SET.length]; + }, ''); +} diff --git a/x-pack/plugins/files/server/file_share_service/index.ts b/x-pack/plugins/files/server/file_share_service/index.ts new file mode 100644 index 00000000000000..dd52ec05777c19 --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export { InternalFileShareService } from './internal_file_share_service'; +export type { + CreateShareArgs, + DeleteArgs as DeleteShareArgs, + DeleteForFileArgs as DeleteSharesForFileArgs, + GetArgs as GetShareArgs, + ListArgs as ListSharesArgs, + UpdateArgs as UpdateShareArgs, +} from './internal_file_share_service'; +export type { FileShareServiceStart } from './types'; diff --git a/x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts b/x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts new file mode 100644 index 00000000000000..7b6f8498b0e3ec --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts @@ -0,0 +1,233 @@ +/* + * 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 moment from 'moment'; +import { + SavedObjectsClientContract, + SavedObject, + ISavedObjectsRepository, + SavedObjectsErrorHelpers, +} from '@kbn/core/server'; +import { nodeBuilder, escapeKuery } from '@kbn/es-query'; +import type { + Pagination, + FileShareJSON, + FileShareJSONWithToken, + FileShare, + UpdatableFileShareMetadata, +} from '../../common/types'; +import { FILE_SO_TYPE } from '../../common/constants'; +import type { File } from '../../common/types'; +import { fileShareObjectType } from '../saved_objects'; +import { generateShareToken } from './generate_share_token'; +import { FileShareServiceStart } from './types'; +import { + ExpiryDateInThePastError, + FileShareNotFoundError, + FileShareTokenInvalidError, +} from './errors'; + +/** + * Arguments for a creating a file share + */ +export interface CreateShareArgs { + /** + * Optionally provide a name for this file share instance + */ + name?: string; + /** + * Optionally set an expiration date as unix timestamp for this file share instance + * + * @note If not specified the file share will expire after 30 days + */ + validUntil?: number; + + /** + * The file object to create the share for + */ + file: File; +} + +/** + * Arguments for listing file shares. + */ +export interface ListArgs extends Pagination { + /** + * The file ID for scope the list to. + */ + fileId?: string; +} + +/** + * ID argument + */ +interface IdArg { + /** + * File share ID. + */ + id: string; +} + +/** + * Delete file share arguments. + */ +export type DeleteArgs = IdArg; +/** + * Get file share arguments. + */ +export type GetArgs = IdArg; + +/** + * Delete file shares for file arguments. + */ +export interface DeleteForFileArgs { + /** + * The file object to delete the shares for. + */ + file: File; +} + +/** + * Update file share arguments. + */ +export interface UpdateArgs { + /** + * The file share ID. + */ + id: string; + /** + * The updated attributes to store. + */ + attributes: UpdatableFileShareMetadata; +} + +function toFileShareJSON(so: SavedObject): FileShareJSON { + return { + id: so.id, + fileId: so.references[0]?.id, // Assuming a single file reference + created: so.attributes.created, + validUntil: so.attributes.valid_until, + name: so.attributes.name, + }; +} + +function validateCreateArgs({ validUntil }: CreateShareArgs): void { + if ((validUntil || validUntil === 0) && validUntil < Date.now()) { + throw new ExpiryDateInThePastError('Share expiry date must be in the future.'); + } +} + +/** + * Service for managing file shares and associated Saved Objects. + * + * @internal + */ +export class InternalFileShareService implements FileShareServiceStart { + private readonly savedObjectsType = fileShareObjectType.name; + + constructor( + private readonly savedObjects: SavedObjectsClientContract | ISavedObjectsRepository + ) {} + + public async share(args: CreateShareArgs): Promise { + validateCreateArgs(args); + const { file, name, validUntil } = args; + const so = await this.savedObjects.create( + this.savedObjectsType, + { + created: new Date().toISOString(), + name, + valid_until: validUntil ? validUntil : Number(moment().add(30, 'days')), + token: generateShareToken(), + }, + { + references: [{ name: file.name, id: file.id, type: FILE_SO_TYPE }], + } + ); + + return { ...toFileShareJSON(so), token: so.attributes.token }; + } + + public async delete({ id }: DeleteArgs): Promise { + try { + await this.savedObjects.delete(this.savedObjectsType, id); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + throw new FileShareNotFoundError(`File share with id "${id}" not found.`); + } + throw e; + } + } + + private async internalList({ + fileId, + perPage, + page, + }: ListArgs): Promise>> { + const result = await this.savedObjects.find({ + type: this.savedObjectsType, + hasReference: fileId + ? { + type: FILE_SO_TYPE, + id: fileId, + } + : undefined, + perPage, + page, + sortField: 'created', + sortOrder: 'desc', + }); + return result.saved_objects; + } + + public async deleteForFile({ file }: DeleteForFileArgs): Promise { + const savedObjects = await this.internalList({ fileId: file.id }); + await Promise.all(savedObjects.map(({ id }) => this.delete({ id }))); + } + + /** + * Get a share token and also check whether it is valid. + */ + public async getByToken(token: string): Promise { + const { + saved_objects: [share], + } = await this.savedObjects.find({ + type: this.savedObjectsType, + filter: nodeBuilder.is(`${this.savedObjectsType}.attributes.token`, escapeKuery(token)), + }); + + if (!share) { + throw new FileShareNotFoundError(`Could not find file share with token "${token}".`); + } + if (share.attributes.valid_until < Date.now() / 1000) { + throw new FileShareTokenInvalidError(`Share "${token}" has expired.`); + } + return toFileShareJSON(share); + } + + public async get({ id }: GetArgs): Promise { + try { + return toFileShareJSON(await this.savedObjects.get(this.savedObjectsType, id)); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + throw new FileShareNotFoundError(e); + } + throw e; + } + } + + public async update({ id, attributes }: UpdateArgs): Promise { + const result = await this.savedObjects.update(this.savedObjectsType, id, attributes); + return { id, ...(result.attributes as FileShare) }; + } + + public async list(args: ListArgs): Promise<{ shares: FileShareJSON[] }> { + const savedObjects = await this.internalList(args); + return { + shares: savedObjects.map(toFileShareJSON), + }; + } +} diff --git a/x-pack/plugins/files/server/file_share_service/types.ts b/x-pack/plugins/files/server/file_share_service/types.ts new file mode 100644 index 00000000000000..bf3147d933083c --- /dev/null +++ b/x-pack/plugins/files/server/file_share_service/types.ts @@ -0,0 +1,43 @@ +/* + * 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 type { FileShareJSON, FileShare } from '../../common/types'; +import type { GetArgs, UpdateArgs, DeleteArgs, ListArgs } from './internal_file_share_service'; + +/** + * We only expose functionality here that do not require you to have a {@link File} + * instance loaded. + */ +export interface FileShareServiceStart { + /** + * Get a share instance + * + * @param {GetArgs} arg - the arguments to get the share instance + */ + get(arg: GetArgs): Promise; + + /** + * List share objects + * + * @param {ListArgs} arg - the arguments to list share objects + */ + list(arg: ListArgs): Promise<{ shares: FileShareJSON[] }>; + + /** + * Update a share instance. + * + * @param {UpdateArgs} args - the arguments to update a share instance + */ + update(args: UpdateArgs): Promise; + + /** + * Delete a share instance. + * + * @param {DeleteArgs} args - the arguments to delete a share instance + */ + delete(args: DeleteArgs): Promise; +} diff --git a/x-pack/plugins/files/server/index.ts b/x-pack/plugins/files/server/index.ts new file mode 100755 index 00000000000000..7b1ecc5ac89ce3 --- /dev/null +++ b/x-pack/plugins/files/server/index.ts @@ -0,0 +1,48 @@ +/* + * 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 type { PluginInitializerContext } from '@kbn/core/server'; +import { FilesPlugin } from './plugin'; + +export type { + FileClient, + FileDescriptor, + GetMetadataArg, + FindMetadataArg, + ListMetadataArg, + UpdateMetadataArg, + DeleteMetedataArg, + FileMetadataClient, + GetUsageMetricsArgs, + CreateEsFileClientArgs, +} from './file_client'; +export { createEsFileClient } from './file_client'; + +export type { FilesSetup, FilesStart } from './types'; +export type { + FileShareServiceStart, + CreateShareArgs, + DeleteShareArgs, + DeleteSharesForFileArgs, + GetShareArgs, + ListSharesArgs, + UpdateShareArgs, +} from './file_share_service'; +export type { + GetByIdArgs, + FindFileArgs, + ListFilesArgs, + CreateFileArgs, + DeleteFileArgs, + UpdateFileArgs, + FileServiceStart, +} from './file_service'; +export type { FileServiceFactory } from './file_service/file_service_factory'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new FilesPlugin(initializerContext); +} diff --git a/x-pack/plugins/files/server/integration_tests/README.md b/x-pack/plugins/files/server/integration_tests/README.md new file mode 100644 index 00000000000000..fb35bc3f0ecc97 --- /dev/null +++ b/x-pack/plugins/files/server/integration_tests/README.md @@ -0,0 +1,10 @@ +## File service integration tests + +The set of tests for File Service integration should cover all file service +functionality. These tests run against an actual Kibana and ES. + +File service is the top-level entry-point for working with files. These integration +tests are closer to functional tests for all of Blob store service, file objects, +file sharing service and file service itself. + +These tests do not include HTTP endpoint tests. diff --git a/x-pack/plugins/files/server/integration_tests/file_service.test.ts b/x-pack/plugins/files/server/integration_tests/file_service.test.ts new file mode 100644 index 00000000000000..0547fe0ed30fbc --- /dev/null +++ b/x-pack/plugins/files/server/integration_tests/file_service.test.ts @@ -0,0 +1,346 @@ +/* + * 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 { CoreStart, ElasticsearchClient } from '@kbn/core/server'; +import { httpServiceMock } from '@kbn/core/server/mocks'; +import { + createTestServers, + createRootWithCorePlugins, + TestElasticsearchUtils, +} from '@kbn/core/test_helpers/kbn_server'; +import { securityMock } from '@kbn/security-plugin/server/mocks'; +import type { AuditLogger } from '@kbn/security-plugin/server'; +import { Readable } from 'stream'; + +import type { FileStatus, File } from '../../common'; + +import { + FileKindsRegistryImpl, + getFileKindsRegistry, + setFileKindsRegistry, +} from '../file_kinds_registry'; +import { BlobStorageService } from '../blob_storage_service'; +import { FileServiceStart, FileServiceFactory } from '../file_service'; +import type { CreateFileArgs } from '../file_service/file_action_types'; + +describe('FileService', () => { + const fileKind: string = 'test'; + const fileKindNonDefault: string = 'test-non-default'; + const fileKindTinyFiles: string = 'tiny-files'; + const nonDefaultIndex = '.kibana-test-files'; + + let manageES: TestElasticsearchUtils; + let kbnRoot: ReturnType; + let fileService: FileServiceStart; + let blobStorageService: BlobStorageService; + let esClient: ElasticsearchClient; + let coreSetup: Awaited>; + let coreStart: CoreStart; + let fileServiceFactory: FileServiceFactory; + let security: ReturnType; + let auditLogger: AuditLogger; + + beforeAll(async () => { + const { startES } = createTestServers({ adjustTimeout: jest.setTimeout }); + manageES = await startES(); + kbnRoot = createRootWithCorePlugins(); + await kbnRoot.preboot(); + coreSetup = await kbnRoot.setup(); + FileServiceFactory.setup(coreSetup.savedObjects); + coreStart = await kbnRoot.start(); + setFileKindsRegistry(new FileKindsRegistryImpl(httpServiceMock.createRouter())); + const fileKindsRegistry = getFileKindsRegistry(); + fileKindsRegistry.register({ + id: fileKind, + http: {}, + }); + fileKindsRegistry.register({ + id: fileKindNonDefault, + http: {}, + blobStoreSettings: { esFixedSizeIndex: { index: nonDefaultIndex } }, + }); + fileKindsRegistry.register({ + id: fileKindTinyFiles, + maxSizeBytes: 10, + http: {}, + }); + esClient = coreStart.elasticsearch.client.asInternalUser; + }); + + afterAll(async () => { + await kbnRoot.shutdown(); + await manageES.stop(); + }); + + beforeEach(() => { + security = securityMock.createSetup(); + auditLogger = { enabled: true, log: jest.fn() }; + (security.audit.asScoped as jest.Mock).mockReturnValue(auditLogger); + security.audit.withoutRequest = auditLogger; + blobStorageService = new BlobStorageService(esClient, kbnRoot.logger.get('test-blob-service')); + fileServiceFactory = new FileServiceFactory( + coreStart.savedObjects, + blobStorageService, + security, + getFileKindsRegistry(), + kbnRoot.logger.get('test-file-service') + ); + fileService = fileServiceFactory.asInternal(); + }); + + let disposables: File[] = []; + async function createDisposableFile(args: CreateFileArgs) { + const file = await fileService.create(args); + disposables.push(file); + return file; + } + afterEach(async () => { + await Promise.all(disposables.map((file) => file.delete())); + const results = await fileService.list({ fileKind }); + expect(results.length).toBe(0); + disposables = []; + }); + + it('creates file metadata awaiting upload', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + expect(file.name).toEqual('test'); + expect(file.fileKind).toEqual(fileKind); + expect(file.status).toBe('AWAITING_UPLOAD' as FileStatus); + expect(auditLogger.log).toHaveBeenCalledTimes(1); + expect(auditLogger.log).toHaveBeenCalledWith({ + error: undefined, + event: { + action: 'create', + outcome: 'success', + }, + message: expect.stringContaining('Created file "test"'), + }); + }); + + it('uploads file content', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + expect(file.status).toBe('AWAITING_UPLOAD' as FileStatus); + await file.uploadContent(Readable.from(['upload this'])); + expect(file.status).toBe('READY' as FileStatus); + const rs = await file.downloadContent(); + const chunks: string[] = []; + for await (const chunk of rs) { + chunks.push(chunk); + } + expect(chunks.join('')).toBe('upload this'); + }); + + it('retrieves a file', async () => { + const { id } = await createDisposableFile({ fileKind, name: 'test' }); + const myFile = await fileService.getById({ id, fileKind }); + expect(myFile?.id).toMatch(id); + }); + + it('lists files', async () => { + await Promise.all([ + createDisposableFile({ fileKind, name: 'test-1' }), + createDisposableFile({ fileKind, name: 'test-2' }), + createDisposableFile({ fileKind, name: 'test-3' }), + createDisposableFile({ fileKind, name: 'test-3' /* Also test file with same name */ }), + ]); + const result = await fileService.list({ fileKind }); + expect(result.length).toBe(4); + }); + + it('deletes files', async () => { + const file = await fileService.create({ fileKind, name: 'test' }); + const files = await fileService.list({ fileKind }); + expect(files.length).toBe(1); + await file.delete(); + expect(await fileService.list({ fileKind })).toEqual([]); + }); + + interface CustomMeta { + some: string; + } + it('updates files', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + const updatableFields = { + name: 'new name', + alt: 'my alt text', + meta: { some: 'data' }, + }; + const updatedFile1 = await file.update(updatableFields); + expect(updatedFile1.meta).toEqual(expect.objectContaining(updatableFields.meta)); + expect(updatedFile1.name).toBe(updatableFields.name); + expect(updatedFile1.alt).toBe(updatableFields.alt); + + // Fetch the file anew to be doubly sure + const updatedFile2 = await fileService.getById({ fileKind, id: file.id }); + expect(updatedFile2.meta).toEqual(expect.objectContaining(updatableFields.meta)); + // Below also tests that our meta type is work as expected by using `some` field. + expect(updatedFile2.meta?.some).toBe(updatableFields.meta.some); + expect(updatedFile2.name).toBe(updatableFields.name); + expect(updatedFile2.alt).toBe(updatableFields.alt); + }); + + it('enforces max size settings', async () => { + const file = await createDisposableFile({ fileKind: fileKindTinyFiles, name: 'test' }); + const tinyContent = Readable.from(['ok']); + await file.uploadContent(tinyContent); + + const file2 = await createDisposableFile({ fileKind: fileKindTinyFiles, name: 'test' }); + const notSoTinyContent = Readable.from(['nok'.repeat(10)]); + await expect(() => file2.uploadContent(notSoTinyContent)).rejects.toThrow( + new Error('Maximum of 10 bytes exceeded') + ); + }); + + describe('ES blob integration and file kinds', () => { + it('passes blob store settings', async () => { + const file = await createDisposableFile({ fileKind: fileKindNonDefault, name: 'test' }); + expect(await esClient.indices.exists({ index: nonDefaultIndex })).toBe(false); + await file.uploadContent(Readable.from(['test'])); + expect(await esClient.indices.exists({ index: nonDefaultIndex })).toBe(true); + }); + }); + + describe('Sharing files', () => { + it('creates a file share object', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + const shareObject = await file.share({ name: 'test name' }); + expect(shareObject).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: 'test name', + validUntil: expect.any(Number), + created: expect.any(String), + token: expect.any(String), + fileId: file.id, + }) + ); + expect(auditLogger.log).toHaveBeenCalledTimes(2); + expect(auditLogger.log).toHaveBeenNthCalledWith(1, { + error: undefined, + event: { + action: 'create', + outcome: 'success', + }, + message: expect.stringContaining('Created file "test"'), + }); + expect(auditLogger.log).toHaveBeenNthCalledWith(2, { + error: undefined, + event: { + action: 'create', + outcome: 'success', + }, + message: expect.stringContaining('Shared file "test"'), + }); + }); + + it('retrieves a a file share object', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + const { id } = await file.share({ name: 'my-file-share' }); + // Check if a file share exists without using an {@link File} object + const result = await fileService.getShareObject({ id }); + expect(result).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: 'my-file-share', + validUntil: expect.any(Number), + created: expect.any(String), + fileId: file.id, + }) + ); + }); + + it('updates a file share object', async () => { + const file = await createDisposableFile({ fileKind, name: 'test' }); + const { id } = await file.share({ name: 'my file share 1' }); + // Check if a file share exists without using an {@link File} object + await fileService.updateShareObject({ id, attributes: { name: 'my file share 2' } }); + const result = await fileService.getShareObject({ id }); + expect(result).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: 'my file share 2', + validUntil: expect.any(Number), + created: expect.any(String), + fileId: file.id, + }) + ); + }); + + it('lists all file share objects for a file', async () => { + const [file, file2] = await Promise.all([ + createDisposableFile({ fileKind, name: 'test' }), + createDisposableFile({ fileKind, name: 'anothertest' }), + ]); + + const [share1] = await Promise.all([ + file.share({ name: 'my-file-share-1' }), + file.share({ name: 'my-file-share-2' }), + file.share({ name: 'my-file-share-3' }), + + file2.share({ name: 'my-file-share-1' }), + file2.share({ name: 'my-file-share-2' }), + file2.share({ name: 'my-file-share-3' }), + ]); + + // Check whether updating file attributes interferes with SO references. + await fileService.updateShareObject({ + id: share1.id, + attributes: { name: 'my-file-share-X' }, + }); + + const shares1 = await file.listShares(); + expect(shares1).toHaveLength(3); + expect(shares1[0]).toEqual( + expect.objectContaining({ + id: expect.any(String), + fileId: file.id, + }) + ); + const shares2 = await file2.listShares(); + expect(await file2.listShares()).toHaveLength(3); + expect(shares2[0]).toEqual( + expect.objectContaining({ + id: expect.any(String), + fileId: file2.id, + }) + ); + }); + + it('deletes a file share object', async () => { + const file = await createDisposableFile({ fileKind, name: 'myfile' }); + const { id } = await file.share({ name: 'my file share' }); + expect(await file.listShares()).toHaveLength(1); + await file.unshare({ shareId: id }); + expect(await file.listShares()).toEqual([]); + expect(auditLogger.log).toHaveBeenCalledTimes(3); + expect(auditLogger.log).toHaveBeenNthCalledWith(1, { + error: undefined, + event: { + action: 'create', + outcome: 'success', + }, + message: expect.stringContaining('Created file "myfile"'), + }); + expect(auditLogger.log).toHaveBeenNthCalledWith(2, { + error: undefined, + event: { + action: 'create', + outcome: 'success', + }, + message: expect.stringContaining('Shared file "myfile"'), + }); + expect(auditLogger.log).toHaveBeenNthCalledWith(3, { + error: undefined, + event: { + action: 'delete', + outcome: 'success', + }, + message: expect.stringContaining('Removed share for "myfile"'), + }); + }); + }); +}); diff --git a/x-pack/plugins/files/server/plugin.ts b/x-pack/plugins/files/server/plugin.ts new file mode 100755 index 00000000000000..61dd86c6d9e150 --- /dev/null +++ b/x-pack/plugins/files/server/plugin.ts @@ -0,0 +1,87 @@ +/* + * 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 type { + PluginInitializerContext, + CoreSetup, + Plugin, + Logger, + CoreStart, +} from '@kbn/core/server'; + +import { PLUGIN_ID } from '../common/constants'; + +import { BlobStorageService } from './blob_storage_service'; +import { FileServiceFactory } from './file_service'; +import type { FilesPluginSetupDependencies, FilesSetup, FilesStart } from './types'; +import { + setFileKindsRegistry, + getFileKindsRegistry, + FileKindsRegistryImpl, +} from './file_kinds_registry'; +import type { FilesRequestHandlerContext, FilesRouter } from './routes/types'; +import { registerRoutes } from './routes'; + +export class FilesPlugin implements Plugin { + private readonly logger: Logger; + private fileServiceFactory: undefined | FileServiceFactory; + private securitySetup: FilesPluginSetupDependencies['security']; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup, deps: FilesPluginSetupDependencies): FilesSetup { + FileServiceFactory.setup(core.savedObjects); + this.securitySetup = deps.security; + + core.http.registerRouteHandlerContext( + PLUGIN_ID, + async (ctx, req) => { + return { + fileService: { + asCurrentUser: () => this.fileServiceFactory!.asScoped(req), + asInternalUser: () => this.fileServiceFactory!.asInternal(), + logger: this.logger.get('files-routes'), + }, + }; + } + ); + + const router: FilesRouter = core.http.createRouter(); + registerRoutes(router); + setFileKindsRegistry(new FileKindsRegistryImpl(router)); + + return { + registerFileKind(fileKind) { + getFileKindsRegistry().register(fileKind); + }, + }; + } + + public start(coreStart: CoreStart): FilesStart { + const { savedObjects } = coreStart; + const esClient = coreStart.elasticsearch.client.asInternalUser; + const blobStorageService = new BlobStorageService( + esClient, + this.logger.get('blob-storage-service') + ); + this.fileServiceFactory = new FileServiceFactory( + savedObjects, + blobStorageService, + this.securitySetup, + getFileKindsRegistry(), + this.logger.get('files-service') + ); + + return { + fileServiceFactory: this.fileServiceFactory, + }; + } + + public stop() {} +} diff --git a/x-pack/plugins/files/server/routes/api_routes.ts b/x-pack/plugins/files/server/routes/api_routes.ts new file mode 100644 index 00000000000000..b40696bfe61e72 --- /dev/null +++ b/x-pack/plugins/files/server/routes/api_routes.ts @@ -0,0 +1,37 @@ +/* + * 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 { + FILES_API_BASE_PATH, + FILES_SHARE_API_BASE_PATH, + FILES_PUBLIC_API_BASE_PATH, + API_BASE_PATH, +} from '../../common/api_routes'; + +export * from '../../common/api_routes'; + +export const FILES_API_ROUTES = { + find: `${API_BASE_PATH}/find`, + metrics: `${API_BASE_PATH}/metrics`, + public: { + download: `${FILES_PUBLIC_API_BASE_PATH}/blob/{fileName?}`, + }, + fileKind: { + getCreateFileRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}`, + getUploadRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}/{id}/blob`, + getDownloadRoute: (fileKind: string) => + `${FILES_API_BASE_PATH}/${fileKind}/{id}/blob/{fileName?}`, + getUpdateRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}/{id}`, + getDeleteRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}/{id}`, + getListRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}/list`, + getByIdRoute: (fileKind: string) => `${FILES_API_BASE_PATH}/${fileKind}/{id}`, + getShareRoute: (fileKind: string) => `${FILES_SHARE_API_BASE_PATH}/${fileKind}/{fileId}`, + getUnshareRoute: (fileKind: string) => `${FILES_SHARE_API_BASE_PATH}/${fileKind}/{id}`, + getGetShareRoute: (fileKind: string) => `${FILES_SHARE_API_BASE_PATH}/${fileKind}/{id}`, + getListShareRoute: (fileKind: string) => `${FILES_SHARE_API_BASE_PATH}/${fileKind}`, + }, +}; diff --git a/x-pack/plugins/files/server/routes/common.test.ts b/x-pack/plugins/files/server/routes/common.test.ts new file mode 100644 index 00000000000000..cda57b5b6bf135 --- /dev/null +++ b/x-pack/plugins/files/server/routes/common.test.ts @@ -0,0 +1,48 @@ +/* + * 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 type { File } from '../file'; +import { getDownloadHeadersForFile } from './common'; + +describe('getDownloadHeadersForFile', () => { + function t({ cd, ct }: { cd: string; ct: string }) { + return { + 'content-type': ct, + 'content-disposition': `attachment; filename="${cd}"`, + }; + } + + const file = { name: 'test', mimeType: undefined } as unknown as File; + test('no mime type and name from file object', () => { + expect(getDownloadHeadersForFile(file, undefined)).toEqual( + t({ ct: 'application/octet-stream', cd: 'test' }) + ); + }); + + test('no mime type and name (without ext)', () => { + expect(getDownloadHeadersForFile(file, 'myfile')).toEqual( + t({ ct: 'application/octet-stream', cd: 'myfile' }) + ); + }); + test('no mime type and name (with ext)', () => { + expect(getDownloadHeadersForFile(file, 'myfile.png')).toEqual( + t({ ct: 'image/png', cd: 'myfile.png' }) + ); + }); + test('mime type and no name', () => { + const fileWithMime = { ...file, mimeType: 'application/pdf' } as File; + expect(getDownloadHeadersForFile(fileWithMime, undefined)).toEqual( + t({ ct: 'application/pdf', cd: 'test' }) + ); + }); + test('mime type and name', () => { + const fileWithMime = { ...file, mimeType: 'application/pdf' } as File; + expect(getDownloadHeadersForFile(fileWithMime, 'a cool file.pdf')).toEqual( + t({ ct: 'application/pdf', cd: 'a cool file.pdf' }) + ); + }); +}); diff --git a/x-pack/plugins/files/server/routes/common.ts b/x-pack/plugins/files/server/routes/common.ts new file mode 100644 index 00000000000000..23f702493c92d2 --- /dev/null +++ b/x-pack/plugins/files/server/routes/common.ts @@ -0,0 +1,27 @@ +/* + * 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 mime from 'mime'; +import type { ResponseHeaders } from '@kbn/core/server'; +import type { File } from '../../common/types'; + +export function getDownloadHeadersForFile(file: File, fileName?: string): ResponseHeaders { + return { + 'content-type': + (fileName && mime.getType(fileName)) ?? file.mimeType ?? 'application/octet-stream', + // Note, this name can be overridden by the client if set via a "download" attribute on the HTML tag. + 'content-disposition': `attachment; filename="${fileName || getDownloadedFileName(file)}"`, + }; +} + +export function getDownloadedFileName(file: File): string { + // When creating a file we also calculate the extension so the `file.extension` + // check is not really necessary except for type checking. + if (file.mimeType && file.extension) { + return `${file.name}.${file.extension}`; + } + return file.name; +} diff --git a/x-pack/plugins/files/server/routes/common_schemas.ts b/x-pack/plugins/files/server/routes/common_schemas.ts new file mode 100644 index 00000000000000..cd254c5c106c94 --- /dev/null +++ b/x-pack/plugins/files/server/routes/common_schemas.ts @@ -0,0 +1,45 @@ +/* + * 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 { schema } from '@kbn/config-schema'; + +const ALPHA_NUMERIC_WITH_SPACES_REGEX = /^[a-z0-9\s]+$/i; +const ALPHA_NUMERIC_WITH_SPACES_EXT_REGEX = /^[a-z0-9\s\.]+$/i; + +function alphanumericValidation(v: string) { + return ALPHA_NUMERIC_WITH_SPACES_REGEX.test(v) + ? undefined + : 'Only alphanumeric characters are allowed as file names'; +} + +function alphanumericWithExtValidation(v: string) { + return ALPHA_NUMERIC_WITH_SPACES_EXT_REGEX.test(v) + ? undefined + : 'Only alphanumeric characters, spaces (" ") and dots (".") are allowed'; +} + +export const fileName = schema.string({ + minLength: 1, + maxLength: 256, + validate: alphanumericValidation, +}); + +export const fileNameWithExt = schema.string({ + minLength: 1, + maxLength: 256, + validate: alphanumericWithExtValidation, +}); + +export const fileAlt = schema.maybe( + schema.string({ + minLength: 1, + maxLength: 256, + validate: alphanumericValidation, + }) +); + +export const fileMeta = schema.maybe(schema.object({}, { unknowns: 'allow' })); diff --git a/x-pack/plugins/files/server/routes/file_kind/create.ts b/x-pack/plugins/files/server/routes/file_kind/create.ts new file mode 100644 index 00000000000000..985b1e8b05a544 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/create.ts @@ -0,0 +1,62 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { Ensure } from '@kbn/utility-types'; +import type { CreateFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKind } from '../../../common/types'; +import { FILES_API_ROUTES } from '../api_routes'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; +import * as commonSchemas from '../common_schemas'; + +export const method = 'post' as const; + +export const bodySchema = schema.object({ + name: commonSchemas.fileName, + alt: commonSchemas.fileAlt, + meta: commonSchemas.fileMeta, + mimeType: schema.maybe(schema.string()), +}); + +type Body = Ensure>; + +type Response = CreateFileKindHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { fileKind, files }, + req, + res +) => { + const { fileService } = await files; + const { + body: { name, alt, meta, mimeType }, + } = req; + const file = await fileService + .asCurrentUser() + .create({ fileKind, name, alt, meta, mime: mimeType }); + const body: Response = { + file: file.toJSON(), + }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.create) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getCreateFileRoute(fileKind.id), + validate: { + body: bodySchema, + }, + options: { + tags: fileKind.http.create.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/delete.ts b/x-pack/plugins/files/server/routes/file_kind/delete.ts new file mode 100644 index 00000000000000..154ae7efe448a5 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/delete.ts @@ -0,0 +1,67 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; +import type { DeleteFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKind } from '../../../common/types'; +import { fileErrors } from '../../file'; +import { FILES_API_ROUTES } from '../api_routes'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; + +import { getById } from './helpers'; + +export const method = 'delete' as const; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); + +type Params = Ensure>; + +type Response = DeleteFileKindHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ({ files, fileKind }, req, res) => { + const { + params: { id }, + } = req; + const { fileService } = await files; + const { error, result: file } = await getById(fileService.asCurrentUser(), id, fileKind); + if (error) return error; + try { + await file.delete(); + } catch (e) { + if ( + e instanceof fileErrors.AlreadyDeletedError || + e instanceof fileErrors.UploadInProgressError + ) { + return res.badRequest({ body: { message: e.message } }); + } + throw e; + } + const body: Response = { + ok: true, + }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.delete) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getDeleteRoute(fileKind.id), + validate: { + params: paramsSchema, + }, + options: { + tags: fileKind.http.delete.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/download.ts b/x-pack/plugins/files/server/routes/file_kind/download.ts new file mode 100644 index 00000000000000..d1ff70d17355f0 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/download.ts @@ -0,0 +1,72 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import { Ensure } from '@kbn/utility-types'; +import { Readable } from 'stream'; + +import type { DownloadFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKind } from '../../../common/types'; +import { fileNameWithExt } from '../common_schemas'; +import { fileErrors } from '../../file'; +import { getDownloadHeadersForFile } from '../common'; +import { getById } from './helpers'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; +import { FILES_API_ROUTES } from '../api_routes'; + +export const method = 'get' as const; + +export const paramsSchema = schema.object({ + id: schema.string(), + fileName: schema.maybe(fileNameWithExt), +}); + +type Params = Ensure>; + +type Response = Readable; + +export const handler: FileKindsRequestHandler = async ( + { files, fileKind }, + req, + res +) => { + const { fileService } = await files; + const { + params: { id, fileName }, + } = req; + const { error, result: file } = await getById(fileService.asCurrentUser(), id, fileKind); + if (error) return error; + try { + const body: Response = await file.downloadContent(); + return res.ok({ + body, + headers: getDownloadHeadersForFile(file, fileName), + }); + } catch (e) { + if (e instanceof fileErrors.NoDownloadAvailableError) { + return res.notFound({ body: { message: e.message } }); + } + throw e; + } +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.download) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getDownloadRoute(fileKind.id), + validate: { + params: paramsSchema, + }, + options: { + tags: fileKind.http.download.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/enhance_router.ts b/x-pack/plugins/files/server/routes/file_kind/enhance_router.ts new file mode 100644 index 00000000000000..b2a4f58fb8fd12 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/enhance_router.ts @@ -0,0 +1,51 @@ +/* + * 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 type { RequestHandler, RouteMethod, RouteRegistrar } from '@kbn/core/server'; + +import { FilesRouter } from '../types'; +import { FileKindRouter, FileKindsRequestHandlerContext } from './types'; + +interface Args { + router: FilesRouter; + fileKind: string; +} + +type FileKindHandler = RequestHandler; + +/** + * Wraps {@link FilesRouter}, adding a middle man for injecting file-kind into + * route handler context + */ +export function enhanceRouter({ router, fileKind }: Args): FileKindRouter { + const handlerWrapper: (handler: FileKindHandler) => FileKindHandler = + (handler) => async (ctx, req, res) => { + return handler( + Object.create(ctx, { fileKind: { value: fileKind, enumerable: true, writeable: false } }), + req, + res + ); + }; + + return new Proxy(router as FileKindRouter, { + get(target, prop, receiver) { + if (['get', 'post', 'put', 'patch', 'delete'].includes(prop as string)) { + const manInTheMiddleRegistrar: RouteRegistrar< + RouteMethod, + FileKindsRequestHandlerContext + > = (opts, handler): void => { + return Reflect.apply(target[prop as keyof FileKindRouter] as Function, target, [ + opts, + handlerWrapper(handler as FileKindHandler), + ]); + }; + return manInTheMiddleRegistrar; + } + return Reflect.get(target, prop, receiver); + }, + }); +} diff --git a/x-pack/plugins/files/server/routes/file_kind/get_by_id.ts b/x-pack/plugins/files/server/routes/file_kind/get_by_id.ts new file mode 100644 index 00000000000000..02c4df0685aea8 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/get_by_id.ts @@ -0,0 +1,53 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; +import type { GetByIdFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKind } from '../../../common/types'; +import { FILES_API_ROUTES } from '../api_routes'; +import { getById } from './helpers'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; + +type Response = GetByIdFileKindHttpEndpoint['output']; + +export const method = 'get' as const; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); +type Params = Ensure>; + +export const handler: FileKindsRequestHandler = async ({ files, fileKind }, req, res) => { + const { fileService } = await files; + const { + params: { id }, + } = req; + const { error, result: file } = await getById(fileService.asCurrentUser(), id, fileKind); + if (error) return error; + const body: Response = { + file: file.toJSON(), + }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.getById) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getByIdRoute(fileKind.id), + validate: { + params: paramsSchema, + }, + options: { + tags: fileKind.http.getById.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/helpers.ts b/x-pack/plugins/files/server/routes/file_kind/helpers.ts new file mode 100644 index 00000000000000..12006fb87837b4 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/helpers.ts @@ -0,0 +1,38 @@ +/* + * 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 { IKibanaResponse, kibanaResponseFactory } from '@kbn/core/server'; +import type { File } from '../../../common'; +import { errors, FileServiceStart } from '../../file_service'; + +type ResultOrHttpError = + | { result: File; error?: undefined } + | { result?: undefined; error: IKibanaResponse }; + +/** + * A helper that given an ID will return a file or map errors to an http response. + */ +export async function getById( + fileService: FileServiceStart, + id: string, + fileKind: string +): Promise { + let result: undefined | File; + try { + result = await fileService.getById({ id, fileKind }); + } catch (e) { + let error: undefined | IKibanaResponse; + if (e instanceof errors.FileNotFoundError) { + error = kibanaResponseFactory.notFound({ body: { message: e.message } }); + } else { + error = kibanaResponseFactory.custom({ statusCode: 500, body: { message: e.message } }); + } + return { error }; + } + + return { result }; +} diff --git a/x-pack/plugins/files/server/routes/file_kind/index.ts b/x-pack/plugins/files/server/routes/file_kind/index.ts new file mode 100644 index 00000000000000..2a85b289f4ea68 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/index.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { FileKind } from '../../../common/types'; + +import { FilesRouter } from '../types'; + +import { enhanceRouter } from './enhance_router'; +import * as create from './create'; +import * as upload from './upload'; +import * as update from './update'; +import * as deleteEndpoint from './delete'; +import * as list from './list'; +import * as download from './download'; +import * as getById from './get_by_id'; +import * as share from './share/share'; +import * as unshare from './share/unshare'; +import * as listShare from './share/list'; +import * as getShare from './share/get'; + +/** + * Register a single file kind's routes + */ +export function registerFileKindRoutes(router: FilesRouter, fileKind: FileKind) { + const fileKindRouter = enhanceRouter({ router, fileKind: fileKind.id }); + [ + create, + upload, + update, + deleteEndpoint, + list, + download, + getById, + share, + unshare, + getShare, + listShare, + ].forEach((route) => { + route.register(fileKindRouter, fileKind); + }); +} diff --git a/x-pack/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts b/x-pack/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts new file mode 100644 index 00000000000000..e4d4bbdf0b2971 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts @@ -0,0 +1,229 @@ +/* + * 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 type { UpdatableFileMetadata } from '../../../../common/types'; +import { setupIntegrationEnvironment, TestEnvironmentUtils } from '../../../test_utils'; + +describe('File kind HTTP API', () => { + let fileKind: string; + let createFile: TestEnvironmentUtils['createFile']; + let root: TestEnvironmentUtils['root']; + let request: TestEnvironmentUtils['request']; + let testHarness: TestEnvironmentUtils; + + beforeAll(async () => { + testHarness = await setupIntegrationEnvironment(); + ({ createFile, root, request, fileKind } = testHarness); + }); + + afterAll(async () => { + await testHarness.cleanupAfterAll(); + }); + + afterEach(async () => { + await testHarness.cleanupAfterEach(); + }); + + test('create a file and return the expected payload', async () => { + expect(await createFile()).toEqual({ + id: expect.any(String), + created: expect.any(String), + updated: expect.any(String), + name: 'myFile', + fileKind, + status: 'AWAITING_UPLOAD', + mimeType: 'image/png', + extension: 'png', + meta: {}, + alt: 'a picture of my dog', + }); + }); + + test('upload a file', async () => { + const { id } = await createFile(); + const result = await request + .put(root, `/api/files/files/${fileKind}/${id}/blob`) + .set('Content-Type', 'application/octet-stream') + .send('what have you') + .expect(200); + expect(result.body).toEqual({ ok: true, size: 13 }); + }); + + test('download a file with the expected header values', async () => { + const { id } = await createFile({ name: 'test' }); + await request + .put(root, `/api/files/files/${fileKind}/${id}/blob`) + .set('content-type', 'application/octet-stream') + .send('what have you') + .expect(200); + + const { body: buffer, header } = await request + .get(root, `/api/files/files/${fileKind}/${id}/blob`) + .set('accept', 'application/octet-stream') + .buffer() + .expect(200); + + expect(header['content-type']).toEqual('image/png'); + expect(header['content-disposition']).toEqual('attachment; filename="test.png"'); + expect(buffer.toString('utf8')).toEqual('what have you'); + }); + + test('update a file', async () => { + const { id } = await createFile({ name: 'acoolfilename' }); + + const { + body: { file }, + } = await request.get(root, `/api/files/files/${fileKind}/${id}`).expect(200); + expect(file.name).toBe('acoolfilename'); + + const updatedFileAttrs: UpdatableFileMetadata = { + name: 'anothercoolfilename', + alt: 'a picture of my cat', + meta: { + something: 'new', + }, + }; + + const { + body: { file: updatedFile }, + } = await request + .patch(root, `/api/files/files/${fileKind}/${id}`) + .send(updatedFileAttrs) + .expect(200); + + expect(updatedFile).toEqual(expect.objectContaining(updatedFileAttrs)); + + const { + body: { file: file2 }, + } = await request.get(root, `/api/files/files/${fileKind}/${id}`).expect(200); + + expect(file2).toEqual(expect.objectContaining(updatedFileAttrs)); + }); + + test('list current files', async () => { + const nrOfFiles = 10; + await Promise.all([...Array(nrOfFiles).keys()].map(() => createFile({ name: 'test' }))); + + const { + body: { files }, + } = await request.get(root, `/api/files/files/${fileKind}/list`).expect(200); + + expect(files).toHaveLength(nrOfFiles); + expect(files[0]).toEqual(expect.objectContaining({ name: 'test' })); + + const { + body: { files: files2 }, + } = await request.get(root, `/api/files/files/${fileKind}/list?page=1&perPage=5`).expect(200); + expect(files2).toHaveLength(5); + }); + + const twoDaysFromNow = (): number => Date.now() + 2 * (1000 * 60 * 60 * 24); + + test('gets a single share object', async () => { + const { id } = await createFile(); + const validUntil = twoDaysFromNow(); + const { + body: { id: shareId }, + } = await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ validUntil, name: 'my-share' }) + .expect(200); + + const { + body: { share }, + } = await request.get(root, `/api/files/shares/${fileKind}/${shareId}`).expect(200); + + expect(share).toEqual( + expect.objectContaining({ + id: shareId, + name: 'my-share', + validUntil, + created: expect.any(String), + fileId: id, + }) + ); + }); + + test('return a share token after sharing a file', async () => { + const { id } = await createFile(); + + const { body: error } = await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ + validUntil: 1, + }) + .expect(400); + + expect(error.message).toContain('must be in the future'); + + const { body: share } = await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ validUntil: twoDaysFromNow(), name: 'my-share' }) + .expect(200); + + expect(share).toEqual( + expect.objectContaining({ + token: expect.any(String), + }) + ); + }); + + test('delete a file share after it was created', async () => { + await request.delete(root, `/api/files/shares/${fileKind}/bogus`).expect(404); + + const { id } = await createFile(); + const { + body: { id: shareId }, + } = await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ validUntil: twoDaysFromNow(), name: 'my-share' }) + .expect(200); + + await request.delete(root, `/api/files/shares/${fileKind}/${shareId}`).expect(200); + await request.get(root, `/api/files/shares/${fileKind}/${shareId}`).expect(404); + }); + + test('list shares', async () => { + { + const { + body: { shares }, + } = await request.get(root, `/api/files/shares/${fileKind}`).expect(200); + expect(shares).toEqual([]); + } + + const { id } = await createFile(); + await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ validUntil: twoDaysFromNow(), name: 'my-share-1' }) + .expect(200); + await request + .post(root, `/api/files/shares/${fileKind}/${id}`) + .send({ validUntil: twoDaysFromNow(), name: 'my-share-2' }) + .expect(200); + + const { id: id2 } = await createFile(); + await request + .post(root, `/api/files/shares/${fileKind}/${id2}`) + .send({ validUntil: twoDaysFromNow(), name: 'my-share-3' }) + .expect(200); + + { + const { + body: { shares }, + } = await request.get(root, `/api/files/shares/${fileKind}?forFileId=${id}`).expect(200); + expect(shares).toHaveLength(2); + // When we list file shares we do not get the file token back + expect(shares[0]).toEqual({ + id: expect.any(String), + created: expect.any(String), + validUntil: expect.any(Number), + name: 'my-share-2', + fileId: id, + }); + } + }); +}); diff --git a/x-pack/plugins/files/server/routes/file_kind/list.ts b/x-pack/plugins/files/server/routes/file_kind/list.ts new file mode 100644 index 00000000000000..3eaa183869b6cb --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/list.ts @@ -0,0 +1,56 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; +import type { ListFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKind } from '../../../common/types'; +import { FILES_API_ROUTES } from '../api_routes'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; + +export const method = 'get' as const; + +export const querySchema = schema.object({ + page: schema.maybe(schema.number({ defaultValue: 1 })), + perPage: schema.maybe(schema.number({ defaultValue: 100 })), +}); + +type Query = Ensure>; + +type Response = ListFileKindHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files, fileKind }, + req, + res +) => { + const { + query: { page, perPage }, + } = req; + const { fileService } = await files; + const response = await fileService.asCurrentUser().list({ fileKind, page, perPage }); + const body: Response = { + files: response.map((result) => result.toJSON()), + }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.list) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getListRoute(fileKind.id), + validate: { + query: querySchema, + }, + options: { + tags: fileKind.http.list.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/share/get.ts b/x-pack/plugins/files/server/routes/file_kind/share/get.ts new file mode 100644 index 00000000000000..7ed01ff444a1f0 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/share/get.ts @@ -0,0 +1,64 @@ +/* + * 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 type { Ensure } from '@kbn/utility-types'; +import { schema, TypeOf } from '@kbn/config-schema'; + +import { FileShareNotFoundError } from '../../../file_share_service/errors'; +import { FileGetShareHttpEndpoint, FILES_API_ROUTES } from '../../api_routes'; +import type { FileKind } from '../../../../common/types'; + +import { FileKindRouter, FileKindsRequestHandler } from '../types'; + +export const method = 'get' as const; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); + +type Params = Ensure>; + +type Response = FileGetShareHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files }, + req, + res +) => { + const { fileService } = await files; + const { + params: { id }, + } = req; + + try { + const body: Response = { share: await fileService.asCurrentUser().getShareObject({ id }) }; + return res.ok({ + body, + }); + } catch (e) { + if (e instanceof FileShareNotFoundError) { + return res.notFound({ body: { message: `File share with id "${id}" not found` } }); + } + throw e; + } +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.share) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getGetShareRoute(fileKind.id), + validate: { + params: paramsSchema, + }, + options: { + tags: fileKind.http.share.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/share/list.ts b/x-pack/plugins/files/server/routes/file_kind/share/list.ts new file mode 100644 index 00000000000000..017f99db9b2e72 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/share/list.ts @@ -0,0 +1,61 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; + +import { FileListSharesHttpEndpoint, FILES_API_ROUTES } from '../../api_routes'; +import type { FileKind } from '../../../../common/types'; +import { FileKindRouter, FileKindsRequestHandler } from '../types'; + +export const method = 'get' as const; + +export const querySchema = schema.object({ + page: schema.maybe(schema.number()), + perPage: schema.maybe(schema.number()), + forFileId: schema.maybe(schema.string()), +}); + +type Query = Ensure>; + +type Response = FileListSharesHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files }, + req, + res +) => { + const { fileService } = await files; + const { + query: { forFileId, page, perPage }, + } = req; + + const result = await fileService + .asCurrentUser() + .listShareObjects({ fileId: forFileId, page, perPage }); + + const body: Response = result; + return res.ok({ + body, + }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.share) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getListShareRoute(fileKind.id), + validate: { + query: querySchema, + }, + options: { + tags: fileKind.http.share.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/share/share.ts b/x-pack/plugins/files/server/routes/file_kind/share/share.ts new file mode 100644 index 00000000000000..0ac43abdb0353e --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/share/share.ts @@ -0,0 +1,95 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; + +import { ExpiryDateInThePastError } from '../../../file_share_service/errors'; +import { FileKindRouter, FileKindsRequestHandler } from '../types'; + +import { FileShareHttpEndpoint, FILES_API_ROUTES } from '../../api_routes'; +import type { FileKind } from '../../../../common/types'; +import { getById } from '../helpers'; + +export const method = 'post' as const; + +export const paramsSchema = schema.object({ + fileId: schema.string(), +}); + +const nameRegex = /^[a-z0-9-_]+$/i; + +export const bodySchema = schema.object({ + validUntil: schema.maybe(schema.number()), + name: schema.maybe( + schema.string({ + maxLength: 256, + validate: (v) => + nameRegex.test(v) ? undefined : 'Only alphanumeric, "-" and "_" characters are allowed.', + }) + ), +}); + +type Body = Ensure>; + +type Params = Ensure>; + +type Response = FileShareHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files, fileKind }, + req, + res +) => { + const { fileService } = await files; + const { + params: { fileId }, + body: { validUntil, name }, + } = req; + + const { error, result: file } = await getById(fileService.asCurrentUser(), fileId, fileKind); + if (error) return error; + + try { + const share = await file.share({ name, validUntil }); + const body: Response = { + id: share.id, + created: share.created, + fileId: share.fileId, + token: share.token, + validUntil: share.validUntil, + name: share.name, + }; + return res.ok({ + body, + }); + } catch (e) { + if (e instanceof ExpiryDateInThePastError) { + return res.badRequest({ + body: e, + }); + } + throw e; + } +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.share) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getShareRoute(fileKind.id), + validate: { + params: paramsSchema, + body: bodySchema, + }, + options: { + tags: fileKind.http.share.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/share/unshare.ts b/x-pack/plugins/files/server/routes/file_kind/share/unshare.ts new file mode 100644 index 00000000000000..ec7cbfb09213e3 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/share/unshare.ts @@ -0,0 +1,67 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; + +import { FILES_API_ROUTES, FileUnshareHttpEndpoint } from '../../api_routes'; +import type { FileKind } from '../../../../common/types'; +import { FileKindRouter, FileKindsRequestHandler } from '../types'; +import { FileShareNotFoundError } from '../../../file_share_service/errors'; + +export const method = 'delete' as const; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); + +type Params = Ensure>; + +type Response = FileUnshareHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files }, + req, + res +) => { + const { fileService } = await files; + const { + params: { id }, + } = req; + + try { + await fileService.asCurrentUser().deleteShareObject({ id }); + } catch (e) { + if (e instanceof FileShareNotFoundError) { + return res.notFound({ body: { message: e.message } }); + } + throw e; + } + + const body: Response = { + ok: true, + }; + return res.ok({ + body, + }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.share) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getUnshareRoute(fileKind.id), + validate: { + params: paramsSchema, + }, + options: { + tags: fileKind.http.share.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/types.ts b/x-pack/plugins/files/server/routes/file_kind/types.ts new file mode 100644 index 00000000000000..19e00663a1d394 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/types.ts @@ -0,0 +1,22 @@ +/* + * 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 type { IRouter, RequestHandler } from '@kbn/core/server'; +import type { FilesRequestHandlerContext } from '../types'; + +export type FileKindRouter = IRouter; + +export interface FileKindsRequestHandlerContext extends FilesRequestHandlerContext { + fileKind: string; +} + +export type FileKindsRequestHandler

= RequestHandler< + P, + Q, + B, + FileKindsRequestHandlerContext +>; diff --git a/x-pack/plugins/files/server/routes/file_kind/update.ts b/x-pack/plugins/files/server/routes/file_kind/update.ts new file mode 100644 index 00000000000000..91a4bcb63d7511 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/update.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Ensure } from '@kbn/utility-types'; +import { schema, TypeOf } from '@kbn/config-schema'; +import type { FileKind } from '../../../common/types'; +import type { UpdateFileKindHttpEndpoint } from '../../../common/api_routes'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; +import { FILES_API_ROUTES } from '../api_routes'; +import { getById } from './helpers'; + +import * as commonSchemas from '../common_schemas'; + +export const method = 'patch' as const; + +export const bodySchema = schema.object({ + name: schema.maybe(commonSchemas.fileName), + alt: schema.maybe(commonSchemas.fileAlt), + meta: schema.maybe(commonSchemas.fileMeta), +}); + +type Body = Ensure>; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); + +type Params = Ensure>; + +type Response = UpdateFileKindHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files, fileKind }, + req, + res +) => { + const { fileService } = await files; + const { + params: { id }, + body: attrs, + } = req; + const { error, result: file } = await getById(fileService.asCurrentUser(), id, fileKind); + if (error) return error; + await file.update(attrs); + const body: Response = { + file: file.toJSON(), + }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.update) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getUpdateRoute(fileKind.id), + validate: { + body: bodySchema, + params: paramsSchema, + }, + options: { + tags: fileKind.http.update.tags, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/file_kind/upload.ts b/x-pack/plugins/files/server/routes/file_kind/upload.ts new file mode 100644 index 00000000000000..7b3db76ad38ad6 --- /dev/null +++ b/x-pack/plugins/files/server/routes/file_kind/upload.ts @@ -0,0 +1,78 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; +import { Readable } from 'stream'; +import type { FileKind } from '../../../common/types'; +import type { UploadFileKindHttpEndpoint } from '../../../common/api_routes'; +import { FILES_API_ROUTES } from '../api_routes'; +import { fileErrors } from '../../file'; +import { getById } from './helpers'; +import type { FileKindRouter, FileKindsRequestHandler } from './types'; + +export const method = 'put' as const; + +export const bodySchema = schema.stream(); +type Body = TypeOf; + +export const paramsSchema = schema.object({ + id: schema.string(), +}); +type Params = Ensure>; + +type Response = UploadFileKindHttpEndpoint['output']; + +export const handler: FileKindsRequestHandler = async ( + { files, fileKind }, + req, + res +) => { + const { fileService } = await files; + const { + body: stream, + params: { id }, + } = req; + const { error, result: file } = await getById(fileService.asCurrentUser(), id, fileKind); + if (error) return error; + try { + await file.uploadContent(stream as Readable); + } catch (e) { + if ( + e instanceof fileErrors.ContentAlreadyUploadedError || + e instanceof fileErrors.UploadInProgressError + ) { + return res.badRequest({ body: { message: e.message } }); + } + throw e; + } + const body: Response = { ok: true, size: file.size! }; + return res.ok({ body }); +}; + +export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { + if (fileKind.http.create) { + fileKindRouter[method]( + { + path: FILES_API_ROUTES.fileKind.getUploadRoute(fileKind.id), + validate: { + body: bodySchema, + params: paramsSchema, + }, + options: { + tags: fileKind.http.create.tags, + body: { + output: 'stream', + parse: false, + accepts: fileKind.allowedMimeTypes ?? 'application/octet-stream', + }, + }, + }, + handler + ); + } +} diff --git a/x-pack/plugins/files/server/routes/find.ts b/x-pack/plugins/files/server/routes/find.ts new file mode 100644 index 00000000000000..6841e4a019841f --- /dev/null +++ b/x-pack/plugins/files/server/routes/find.ts @@ -0,0 +1,81 @@ +/* + * 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 { schema, TypeOf } from '@kbn/config-schema'; +import type { Ensure } from '@kbn/utility-types'; +import type { FilesRouter } from './types'; + +import { FindFilesHttpEndpoint, FILES_API_ROUTES } from './api_routes'; +import type { FilesRequestHandler } from './types'; + +const method = 'post' as const; + +const string64 = schema.string({ maxLength: 64 }); +const string256 = schema.string({ maxLength: 256 }); + +const stringOrArrayOfStrings = schema.oneOf([string64, schema.arrayOf(string64)]); +const nameStringOrArrayOfNameStrings = schema.oneOf([string256, schema.arrayOf(string256)]); + +const bodySchema = schema.object({ + kind: schema.maybe(stringOrArrayOfStrings), + status: schema.maybe(stringOrArrayOfStrings), + name: schema.maybe(nameStringOrArrayOfNameStrings), + meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}); + +const querySchema = schema.object({ + page: schema.maybe(schema.number()), + perPage: schema.maybe(schema.number({ defaultValue: 100 })), +}); + +type Body = Ensure>; + +type Query = Ensure>; + +type Response = FindFilesHttpEndpoint['output']; + +function toArray(val: string | string[]) { + return Array.isArray(val) ? val : [val]; +} + +const handler: FilesRequestHandler = async ({ files }, req, res) => { + const { fileService } = await files; + const { + body: { meta, extension, kind, name, status }, + query, + } = req; + + const body: Response = { + files: await fileService.asCurrentUser().find({ + kind: kind && toArray(kind), + name: name && toArray(name), + status: status && toArray(status), + extension: extension && toArray(extension), + meta, + ...query, + }), + }; + return res.ok({ + body, + }); +}; + +// TODO: Find out whether we want to add stricter access controls to this route. +// Currently this is giving read-access to all files which bypasses the +// security we set up on a per route level for the "getById" and "list" endpoints. +// Alternatively, we can remove the access controls on the "file kind" endpoints +// or remove them entirely. +export function register(router: FilesRouter) { + router[method]( + { + path: FILES_API_ROUTES.find, + validate: { + body: bodySchema, + }, + }, + handler + ); +} diff --git a/x-pack/plugins/files/server/routes/index.ts b/x-pack/plugins/files/server/routes/index.ts new file mode 100644 index 00000000000000..5d17cb2292e4c2 --- /dev/null +++ b/x-pack/plugins/files/server/routes/index.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 { FilesRouter } from './types'; + +import * as find from './find'; +import * as metrics from './metrics'; +import * as publicDownload from './public_facing/download'; + +export function registerRoutes(router: FilesRouter) { + [find, metrics, publicDownload].forEach((endpoint) => { + endpoint.register(router); + }); +} diff --git a/x-pack/plugins/files/server/routes/integration_tests/routes.test.ts b/x-pack/plugins/files/server/routes/integration_tests/routes.test.ts new file mode 100644 index 00000000000000..a01f377a0364ba --- /dev/null +++ b/x-pack/plugins/files/server/routes/integration_tests/routes.test.ts @@ -0,0 +1,245 @@ +/* + * 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 type { CreateFileKindHttpEndpoint } from '../../../common/api_routes'; +import { setupIntegrationEnvironment, TestEnvironmentUtils } from '../../test_utils'; + +describe('File HTTP API', () => { + let testHarness: TestEnvironmentUtils; + let root: TestEnvironmentUtils['root']; + let request: TestEnvironmentUtils['request']; + let createFile: TestEnvironmentUtils['createFile']; + let fileKind: string; + + beforeAll(async () => { + testHarness = await setupIntegrationEnvironment(); + ({ request, createFile, root, fileKind } = testHarness); + }); + + afterAll(async () => { + await testHarness.cleanupAfterAll(); + }); + + describe('find', () => { + beforeEach(async () => { + const args: Array = [ + { + name: 'firstFile', + alt: 'my first alt', + meta: { + cool: 'beans', + }, + mimeType: 'image/png', + }, + { + name: 'secondFile', + alt: 'my second alt', + meta: { + other: 'beans', + }, + mimeType: 'application/pdf', + }, + { + name: 'thirdFile', + alt: 'my first alt', + meta: { + cool: 'bones', + }, + mimeType: 'image/png', + }, + ]; + + const files = await Promise.all(args.map((arg) => createFile(arg))); + + for (const file of files.slice(0, 2)) { + await request + .put(root, `/api/files/files/${testHarness.fileKind}/${file.id}/blob`) + .set('Content-Type', 'application/octet-stream') + .send('hello world') + .expect(200); + } + }); + afterEach(async () => { + await testHarness.cleanupAfterEach(); + }); + + test('without filters', async () => { + const result = await request.post(root, '/api/files/find').send({}).expect(200); + expect(result.body.files).toHaveLength(3); + }); + + test('names', async () => { + const result = await request + .post(root, '/api/files/find') + .send({ name: ['firstFile', 'secondFile'] }) + .expect(200); + expect(result.body.files).toHaveLength(2); + }); + + test('file kind', async () => { + { + const result = await request + .post(root, `/api/files/find`) + .send({ kind: 'non-existent' }) + .expect(200); + expect(result.body.files).toHaveLength(0); + } + + { + const result = await request + .post(root, '/api/files/find') + .send({ kind: testHarness.fileKind }) + .expect(200); + expect(result.body.files).toHaveLength(3); + } + }); + + test('status', async () => { + const result = await request + .post(root, '/api/files/find') + .send({ + status: 'READY', + }) + .expect(200); + expect(result.body.files).toHaveLength(2); + }); + + test('combination', async () => { + const result = await request + .post(root, '/api/files/find') + .send({ + kind: testHarness.fileKind, + name: ['firstFile', 'secondFile'], + meta: { cool: 'beans' }, + }) + .expect(200); + expect(result.body.files).toHaveLength(1); + }); + }); + + describe('metrics', () => { + const esMaxCapacity = 50 * 1024 * 1024 * 1024; + afterEach(async () => { + await testHarness.cleanupAfterEach(); + }); + test('returns usage metrics', async () => { + { + const { body: metrics } = await request.get(root, '/api/files/metrics').expect(200); + expect(metrics).toEqual({ + countByExtension: {}, + countByStatus: {}, + storage: { + esFixedSizeIndex: { + capacity: esMaxCapacity, + available: esMaxCapacity, + used: 0, + }, + }, + }); + } + + const [file1, file2] = await Promise.all([createFile(), createFile(), createFile()]); + + { + const { body: metrics } = await request.get(root, '/api/files/metrics').expect(200); + expect(metrics).toEqual({ + countByExtension: { + png: 3, + }, + countByStatus: { + AWAITING_UPLOAD: 3, + }, + storage: { + esFixedSizeIndex: { + capacity: esMaxCapacity, + available: esMaxCapacity, + used: 0, + }, + }, + }); + } + + const { + body: { size: size1 }, + } = await request + .put(root, `/api/files/files/${fileKind}/${file1.id}/blob`) + .set('Content-Type', 'application/octet-stream') + .send('what have you') + .expect(200); + const { + body: { size: size2 }, + } = await request + .put(root, `/api/files/files/${fileKind}/${file2.id}/blob`) + .set('Content-Type', 'application/octet-stream') + .send('what have you') + .expect(200); + + { + const { body: metrics } = await request.get(root, '/api/files/metrics').expect(200); + expect(metrics).toEqual({ + countByExtension: { + png: 3, + }, + countByStatus: { + AWAITING_UPLOAD: 1, + READY: 2, + }, + storage: { + esFixedSizeIndex: { + capacity: esMaxCapacity, + available: esMaxCapacity - size1 - size2, + used: size1 + size2, + }, + }, + }); + } + }); + }); + + describe('public download', () => { + afterEach(async () => { + await testHarness.cleanupAfterEach(); + }); + test('it returns 400 for an invalid token', async () => { + await request.get(root, `/api/files/public/blob/myfilename.pdf`).expect(400); + const { body: response } = await request + .get(root, `/api/files/public/blob/myfilename.pdf?token=notavalidtoken`) + .expect(400); + + expect(response.message).toMatch('Invalid token'); + }); + + test('it downloads a publicly shared file', async () => { + const { id } = await createFile(); + + const { + body: { token }, + } = await request.post(root, `/api/files/shares/${fileKind}/${id}`).send({}).expect(200); + + await request + .get(root, `/api/files/public/blob/myfilename.pdf?token=${token}`) + .buffer() + .expect(400); + + await request + .put(root, `/api/files/files/${fileKind}/${id}/blob`) + .set('Content-Type', 'application/octet-stream') + .send('test') + .expect(200); + + const { body: buffer, header } = await request + // By providing a file name like "myfilename.pdf" we imply that we want a pdf + .get(root, `/api/files/public/blob/myfilename.pdf?token=${token}`) + .buffer() + .expect(200); + + expect(header['content-type']).toEqual('application/pdf'); + expect(header['content-disposition']).toEqual('attachment; filename="myfilename.pdf"'); + expect(buffer.toString('utf8')).toEqual('test'); + }); + }); +}); diff --git a/x-pack/plugins/files/server/routes/metrics.ts b/x-pack/plugins/files/server/routes/metrics.ts new file mode 100644 index 00000000000000..5d7e08773c04ed --- /dev/null +++ b/x-pack/plugins/files/server/routes/metrics.ts @@ -0,0 +1,32 @@ +/* + * 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 type { FilesRouter } from './types'; + +import { FilesMetricsHttpEndpoint, FILES_API_ROUTES } from './api_routes'; +import type { FilesRequestHandler } from './types'; + +const method = 'get' as const; + +type Response = FilesMetricsHttpEndpoint['output']; + +const handler: FilesRequestHandler = async ({ files }, req, res) => { + const { fileService } = await files; + const body: Response = await fileService.asCurrentUser().getUsageMetrics(); + return res.ok({ + body, + }); +}; + +export function register(router: FilesRouter) { + router[method]( + { + path: FILES_API_ROUTES.metrics, + validate: {}, + }, + handler + ); +} diff --git a/x-pack/plugins/files/server/routes/public_facing/download.ts b/x-pack/plugins/files/server/routes/public_facing/download.ts new file mode 100644 index 00000000000000..fd908c2ca8abdb --- /dev/null +++ b/x-pack/plugins/files/server/routes/public_facing/download.ts @@ -0,0 +1,86 @@ +/* + * 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 type { Ensure } from '@kbn/utility-types'; +import { schema, TypeOf } from '@kbn/config-schema'; + +import { NoDownloadAvailableError } from '../../file/errors'; +import { FileNotFoundError } from '../../file_service/errors'; +import { + FileShareNotFoundError, + FileShareTokenInvalidError, +} from '../../file_share_service/errors'; +import type { FilesRouter, FilesRequestHandler } from '../types'; +import { FilePublicDownloadHttpEndpoint, FILES_API_ROUTES } from '../api_routes'; +import { getDownloadHeadersForFile } from '../common'; +import { fileNameWithExt } from '../common_schemas'; + +const method = 'get' as const; + +const querySchema = schema.object({ + token: schema.string(), +}); + +export const paramsSchema = schema.object({ + fileName: schema.maybe(fileNameWithExt), +}); + +type Query = Ensure>; + +type Params = Ensure< + FilePublicDownloadHttpEndpoint['inputs']['params'], + TypeOf +>; + +type Response = FilePublicDownloadHttpEndpoint['output']; + +const handler: FilesRequestHandler = async ({ files }, req, res) => { + const { fileService } = await files; + const { + query: { token }, + params: { fileName }, + } = req; + + try { + const file = await fileService.asInternalUser().getByToken(token); + const body: Response = await file.downloadContent(); + return res.ok({ + body, + headers: getDownloadHeadersForFile(file, fileName), + }); + } catch (e) { + if ( + e instanceof FileNotFoundError || + e instanceof FileShareNotFoundError || + e instanceof FileShareTokenInvalidError + ) { + return res.badRequest({ body: { message: 'Invalid token' } }); + } + if (e instanceof NoDownloadAvailableError) { + return res.badRequest({ + body: { message: 'No download available. Try uploading content to the file first.' }, + }); + } + + throw e; + } +}; + +export function register(router: FilesRouter) { + router[method]( + { + path: FILES_API_ROUTES.public.download, + validate: { + query: querySchema, + params: paramsSchema, + }, + options: { + authRequired: false, + }, + }, + handler + ); +} diff --git a/x-pack/plugins/files/server/routes/types.ts b/x-pack/plugins/files/server/routes/types.ts new file mode 100644 index 00000000000000..eccc55e769e589 --- /dev/null +++ b/x-pack/plugins/files/server/routes/types.ts @@ -0,0 +1,38 @@ +/* + * 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 type { + RequestHandlerContext, + IRouter, + RequestHandler, + RouteMethod, + KibanaResponseFactory, + IKibanaResponse, + Logger, +} from '@kbn/core/server'; +import type { FileServiceStart } from '../file_service'; + +export interface FilesRequestHandlerContext extends RequestHandlerContext { + files: Promise<{ + fileService: { + asCurrentUser: () => FileServiceStart; + asInternalUser: () => FileServiceStart; + logger: Logger; + }; + }>; +} + +export type FilesRouter = IRouter; + +export type FilesRequestHandler< + P = unknown, + Q = unknown, + B = unknown, + Method extends RouteMethod = any +> = RequestHandler; + +export type AsyncResponse = Promise>; diff --git a/x-pack/plugins/files/server/saved_objects/file.ts b/x-pack/plugins/files/server/saved_objects/file.ts new file mode 100644 index 00000000000000..352a00016f86d2 --- /dev/null +++ b/x-pack/plugins/files/server/saved_objects/file.ts @@ -0,0 +1,58 @@ +/* + * 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 { SavedObjectsType, SavedObjectsFieldMapping } from '@kbn/core/server'; +import { FILE_SO_TYPE } from '../../common'; +import type { FileMetadata } from '../../common'; + +type Properties = Record< + keyof Omit, + SavedObjectsFieldMapping +>; + +const properties: Properties = { + created: { + type: 'date', + }, + Updated: { + type: 'date', + }, + name: { + type: 'text', + }, + Status: { + type: 'keyword', + }, + mime_type: { + type: 'keyword', + }, + extension: { + type: 'keyword', + }, + size: { + type: 'long', + }, + Meta: { + type: 'flattened', + }, + FileKind: { + type: 'keyword', + }, +}; + +export const fileObjectType: SavedObjectsType = { + name: FILE_SO_TYPE, + hidden: true, + namespaceType: 'multiple-isolated', + management: { + importableAndExportable: false, + }, + mappings: { + dynamic: false, + properties, + }, +}; diff --git a/x-pack/plugins/files/server/saved_objects/file_share.ts b/x-pack/plugins/files/server/saved_objects/file_share.ts new file mode 100644 index 00000000000000..e71253582b3815 --- /dev/null +++ b/x-pack/plugins/files/server/saved_objects/file_share.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectsFieldMapping, SavedObjectsType } from '@kbn/core/server'; +import type { FileShare } from '../../common/types'; +import { FILE_SHARE_SO_TYPE } from '../../common/constants'; + +/** + * This saved object represents an instance of a publicly shared file. + * + * This file should be accessible to anyone who can access this Kibana over the + * Internet. + */ + +type Properties = Record; + +const properties: Properties = { + created: { + type: 'date', + }, + valid_until: { + type: 'long', + }, + token: { + type: 'keyword', + }, + name: { + type: 'keyword', + }, +}; + +export const fileShareObjectType: SavedObjectsType = { + name: FILE_SHARE_SO_TYPE, + hidden: true, + namespaceType: 'agnostic', // These saved objects should be visible everywhere + mappings: { + dynamic: false, + properties, + }, +}; diff --git a/x-pack/plugins/files/server/saved_objects/index.ts b/x-pack/plugins/files/server/saved_objects/index.ts new file mode 100644 index 00000000000000..42fda22db97c13 --- /dev/null +++ b/x-pack/plugins/files/server/saved_objects/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { fileObjectType } from './file'; +export { fileShareObjectType } from './file_share'; diff --git a/x-pack/plugins/files/server/test_utils/index.ts b/x-pack/plugins/files/server/test_utils/index.ts new file mode 100644 index 00000000000000..98215f70649db8 --- /dev/null +++ b/x-pack/plugins/files/server/test_utils/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { setupIntegrationEnvironment } from './setup_integration_environment'; +export type { TestEnvironmentUtils } from './setup_integration_environment'; diff --git a/x-pack/plugins/files/server/test_utils/setup_integration_environment.ts b/x-pack/plugins/files/server/test_utils/setup_integration_environment.ts new file mode 100644 index 00000000000000..81d04c23bdc963 --- /dev/null +++ b/x-pack/plugins/files/server/test_utils/setup_integration_environment.ts @@ -0,0 +1,131 @@ +/* + * 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 { defaults } from 'lodash'; +import { + createRootWithCorePlugins, + createTestServers, + request, +} from '@kbn/core/test_helpers/kbn_server'; +import pRetry from 'p-retry'; +import { FileJSON } from '../../common'; +import { getFileKindsRegistry } from '../file_kinds_registry'; + +export type TestEnvironmentUtils = Awaited>; + +export async function setupIntegrationEnvironment() { + const fileKind: string = 'test-file-kind'; + const testIndex = '.kibana-test-files'; + const testConfig = { + xpack: { + reporting: { enabled: false }, + }, + }; + + /** + * Functionality to create files easily + */ + let disposables: Array<() => Promise> = []; + const createFile = async ( + fileAttrs: Partial<{ + name: string; + alt: string; + meta: Record; + mimeType: string; + }> = {} + ): Promise => { + const result = await request + .post(root, `/api/files/files/${fileKind}`) + .send( + defaults(fileAttrs, { + name: 'myFile', + alt: 'a picture of my dog', + meta: {}, + mimeType: 'image/png', + }) + ) + .expect(200); + disposables.push(async () => { + await request + .delete(root, `/api/files/files/${fileKind}/${result.body.file.id}`) + .send() + .expect(200); + }); + return result.body.file; + }; + + const { startES } = createTestServers({ + adjustTimeout: jest.setTimeout, + settings: { + es: { + license: 'basic', + }, + }, + }); + + /** + * Clean up methods + */ + const cleanupAfterEach = async () => { + await Promise.all(disposables.map((dispose) => dispose())); + disposables = []; + await esClient.indices.delete({ index: testIndex, ignore_unavailable: true }); + }; + const cleanupAfterAll = async () => { + await root.shutdown(); + await manageES.stop(); + }; + + /** + * Start the servers and set them up + */ + const manageES = await startES(); + + const root = createRootWithCorePlugins(testConfig, { oss: false }); + await root.preboot(); + await root.setup(); + + /** + * Register a test file type + */ + const testHttpConfig = { tags: ['access:myapp'] }; + getFileKindsRegistry().register({ + id: fileKind, + blobStoreSettings: { + esFixedSizeIndex: { index: testIndex }, + }, + http: { + create: testHttpConfig, + delete: testHttpConfig, + update: testHttpConfig, + download: testHttpConfig, + getById: testHttpConfig, + list: testHttpConfig, + share: testHttpConfig, + }, + }); + const coreStart = await root.start(); + const esClient = coreStart.elasticsearch.client.asInternalUser; + + /** + * Wait for endpoints to be available + */ + await pRetry(() => request.get(root, '/api/licensing/info').expect(200), { retries: 5 }); + + return { + manageES, + esClient, + root, + coreStart, + fileKind, + testIndex, + request, + createFile, + cleanupAfterEach, + cleanupAfterAll, + }; +} diff --git a/x-pack/plugins/files/server/types.ts b/x-pack/plugins/files/server/types.ts new file mode 100644 index 00000000000000..86ff4e5ae3c193 --- /dev/null +++ b/x-pack/plugins/files/server/types.ts @@ -0,0 +1,36 @@ +/* + * 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 type { SecurityPluginSetup } from '@kbn/security-plugin/server'; +import { FileKind } from '../common'; +import { FileServiceFactory } from './file_service/file_service_factory'; + +/** + * Files plugin setup contract + */ +export interface FilesSetup { + /** + * Register a {@link FileKind} which allows for specifying details about the files + * that will be uploaded. + * + * @param {FileKind} fileKind - the file kind to register + */ + registerFileKind(fileKind: FileKind): void; +} + +export interface FilesPluginSetupDependencies { + security?: SecurityPluginSetup; +} + +/** + * Files plugin start contract + */ +export interface FilesStart { + /** + * Create an instance of {@link FileServiceStart}. + */ + fileServiceFactory: FileServiceFactory; +} diff --git a/x-pack/plugins/files/tsconfig.json b/x-pack/plugins/files/tsconfig.json new file mode 100644 index 00000000000000..a2c2e1e8ebd3f4 --- /dev/null +++ b/x-pack/plugins/files/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": ["common/**/*", "public/**/*", "server/**/*"], + "references": [ + { "path": "../../../src/core/tsconfig.json" }, + { "path": "../security/tsconfig.json" }, + ] +} diff --git a/yarn.lock b/yarn.lock index ed1c990ccdbd38..d9a9902bbc4d0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,6 +1239,36 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@cbor-extract/cbor-extract-darwin-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76" + integrity sha512-jebtLrruvsBbGMsUn0QxZW/8Z7caS9OkszVKZ64WTWajUkyohmolUdKL2nbfaTyyi3ABJrxVNM4YO1pvMsNI1g== + +"@cbor-extract/cbor-extract-darwin-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.0.0.tgz#7bc01e7911b97eee4c78ae074bd3108f2ff208c3" + integrity sha512-LGYjdlyqANBqCDzBujCqXpPcK70rvaQgw98/aquzBuEmK0KXS7i579CoVG1yS/eb3bMqiVPevBri45jbR6Tlsg== + +"@cbor-extract/cbor-extract-linux-arm64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.0.0.tgz#e40608afed5f373091560fa9dcd19c7f52f510b0" + integrity sha512-c1rbQcSF01yVgbG60zEfHNsUkXiEEQRNdYqm5qpqEAkLx4gA6DDU91IQbalkqXfwDuQzcMovOc1TC3uJJIi2OQ== + +"@cbor-extract/cbor-extract-linux-arm@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.0.0.tgz#f52a7580fb23e305370e66ae9ff136de3729c4b8" + integrity sha512-cOGHEIif5rPbpix6qhpuatrZzm6HeC5rT0nXt8ynLTc7PzfXmovswD9x6d9h5NcHswkV5y3PbkNbpel/tLADYg== + +"@cbor-extract/cbor-extract-linux-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.0.0.tgz#8c936b8a93f915bf3c2459d5b4b78d244bda0f26" + integrity sha512-WYeE1b5WGf9pbbQH3qeNBXq710gGsuVFUiP148RY8In+2pCp/fxjBpe701ngam9/fF5D+gJs8B1i5wv/PN7JZA== + +"@cbor-extract/cbor-extract-win32-x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.0.0.tgz#4d4ad91527a8313c3db1e2167a8821dfae9d6211" + integrity sha512-XqVuJEnE0jpl/RkuSp04FF2UE73gY52Y4nZaIE6j9GAeSH2cHYU5CCd4TaVMDi2M18ZpZv7XhL/k+nneQzyJpQ== + "@cnakazawa/watch@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" @@ -11148,6 +11178,27 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +cbor-extract@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-2.0.2.tgz#8e45339627fb8b47071e8e71138c630019125939" + integrity sha512-QoLGEgPff03ad/L66P91ci5Zmf7Woq8bh4H5XT3+D5annlrPH5ObHf2Yvo53eDQaDkQtF9tJwMKSWANGXDmwUA== + dependencies: + node-gyp-build-optional-packages "5.0.3" + optionalDependencies: + "@cbor-extract/cbor-extract-darwin-arm64" "2.0.0" + "@cbor-extract/cbor-extract-darwin-x64" "2.0.0" + "@cbor-extract/cbor-extract-linux-arm" "2.0.0" + "@cbor-extract/cbor-extract-linux-arm64" "2.0.0" + "@cbor-extract/cbor-extract-linux-x64" "2.0.0" + "@cbor-extract/cbor-extract-win32-x64" "2.0.0" + +cbor-x@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.3.3.tgz#5ba0f6d3f6720ea5ba38804e583c020bccf2f762" + integrity sha512-y3V8GlypWM01t3NtYvXmDehuU3bt4q3tewCrvj5EMfUYT6v9HjRu4NHYH3EgbzJCOaZFroAhzci9PHvIIDuOEQ== + optionalDependencies: + cbor-extract "^2.0.2" + ccount@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17" @@ -12490,6 +12541,11 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== +cuid@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/cuid/-/cuid-2.1.8.tgz#cbb88f954171e0d5747606c0139fb65c5101eac0" + integrity sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg== + cwise-compiler@^1.0.0, cwise-compiler@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5" @@ -21106,6 +21162,11 @@ node-forge@^1, node-forge@^1.2.1, node-forge@^1.3.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-gyp-build-optional-packages@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" + integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== + node-gyp-build@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739" From ca75531de25f4bb12b1a27cbe011c220b91ba890 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Thu, 11 Aug 2022 12:58:21 +0200 Subject: [PATCH 11/59] [kbn-performance-testing-dataset-extractor] organise kibana concurrent calls into streams (#138263) * use streams for both es and kibana calls * improve run speed * update comments * fixes for review * update test * use msearch to get all ES requests * remove unused method * Update packages/kbn-performance-testing-dataset-extractor/src/es_client.ts Co-authored-by: Spencer * fix code * specify index * check span is defined Co-authored-by: Spencer --- .../jest.config.js | 2 +- .../src/cli.ts | 3 +- .../src/constants.ts | 9 ++ .../src/es_client.ts | 48 +++++- .../src/es_request.ts | 139 ------------------ .../src/extractor.ts | 47 ++---- .../src/request.ts | 106 +++++++++++++ .../src/server_request.ts | 85 ----------- .../src/stream.test.ts | 80 ++++++++++ .../src/stream.ts | 57 +++++++ .../src/types.ts | 59 ++++++++ 11 files changed, 367 insertions(+), 268 deletions(-) create mode 100644 packages/kbn-performance-testing-dataset-extractor/src/constants.ts delete mode 100644 packages/kbn-performance-testing-dataset-extractor/src/es_request.ts create mode 100644 packages/kbn-performance-testing-dataset-extractor/src/request.ts delete mode 100644 packages/kbn-performance-testing-dataset-extractor/src/server_request.ts create mode 100644 packages/kbn-performance-testing-dataset-extractor/src/stream.test.ts create mode 100644 packages/kbn-performance-testing-dataset-extractor/src/stream.ts create mode 100644 packages/kbn-performance-testing-dataset-extractor/src/types.ts diff --git a/packages/kbn-performance-testing-dataset-extractor/jest.config.js b/packages/kbn-performance-testing-dataset-extractor/jest.config.js index e31a2d79968931..4800a9edea7c53 100644 --- a/packages/kbn-performance-testing-dataset-extractor/jest.config.js +++ b/packages/kbn-performance-testing-dataset-extractor/jest.config.js @@ -7,7 +7,7 @@ */ module.exports = { - preset: '@kbn/test/jest_node', + preset: '@kbn/test', rootDir: '../..', roots: ['/packages/kbn-performance-testing-dataset-extractor'], }; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/cli.ts b/packages/kbn-performance-testing-dataset-extractor/src/cli.ts index 914a7d587efdfe..37be456d66aa13 100644 --- a/packages/kbn-performance-testing-dataset-extractor/src/cli.ts +++ b/packages/kbn-performance-testing-dataset-extractor/src/cli.ts @@ -16,7 +16,8 @@ import { run } from '@kbn/dev-cli-runner'; import { createFlagError } from '@kbn/dev-cli-errors'; import { EsVersion, readConfigFile } from '@kbn/test'; import path from 'path'; -import { extractor, ScalabilitySetup } from './extractor'; +import { extractor } from './extractor'; +import { ScalabilitySetup } from './types'; interface Vars { [key: string]: string; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/constants.ts b/packages/kbn-performance-testing-dataset-extractor/src/constants.ts new file mode 100644 index 00000000000000..a9dc0b9d2ffbe4 --- /dev/null +++ b/packages/kbn-performance-testing-dataset-extractor/src/constants.ts @@ -0,0 +1,9 @@ +/* + * 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 const DATE_FORMAT = `YYYY-MM-DD'T'HH:mm:ss.SSS'Z'`; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/es_client.ts b/packages/kbn-performance-testing-dataset-extractor/src/es_client.ts index 948d410c8669e1..c878f148e4e675 100644 --- a/packages/kbn-performance-testing-dataset-extractor/src/es_client.ts +++ b/packages/kbn-performance-testing-dataset-extractor/src/es_client.ts @@ -8,7 +8,7 @@ import { Client } from '@elastic/elasticsearch'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { SearchRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { SearchRequest, MsearchRequestItem } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ToolingLog } from '@kbn/tooling-log'; interface ClientOptions { @@ -36,6 +36,7 @@ interface Transaction { name: string; type: string; duration: { us: number }; + span_count: { started: number }; } export interface Document { @@ -98,6 +99,7 @@ const addRangeFilter = (range: { startTime: string; endTime: string }): QueryDsl export class ESClient { client: Client; log: ToolingLog; + tracesIndex: string = '.ds-traces-apm-default*'; constructor(options: ClientOptions, log: ToolingLog) { this.client = new Client({ @@ -112,6 +114,7 @@ export class ESClient { async getTransactions(queryFilters: QueryDslQueryContainer[]) { const searchRequest: SearchRequest = { + index: this.tracesIndex, body: { sort: [ { @@ -172,9 +175,44 @@ export class ESClient { return await this.getTransactions(queryFilters); } - async getSpans(transactionId: string) { - const filters = [{ field: 'parent.id', value: transactionId }]; - const queryFilters = filters.map((filter) => addBooleanFilter(filter)); - return await this.getTransactions(queryFilters); + getMsearchRequestItem = (queryFilters: QueryDslQueryContainer[]): MsearchRequestItem => { + return { + query: { + bool: { + filter: [ + { + bool: { + filter: queryFilters, + }, + }, + ], + }, + }, + }; + }; + + async getSpans(transactionIds: string[]) { + const searches = new Array(); + + for (const transactionId of transactionIds) { + const filters = [{ field: 'parent.id', value: transactionId }]; + const queryFilters = filters.map((filter) => addBooleanFilter(filter)); + const requestItem = this.getMsearchRequestItem(queryFilters); + searches.push({ index: this.tracesIndex }, requestItem); + } + this.log.debug(`Msearch request: ${JSON.stringify(searches)}`); + const result = await this.client.msearch({ + searches, + }); + this.log.debug(`Msearch result: ${JSON.stringify(result)}`); + return result.responses.flatMap((response) => { + if ('error' in response) { + throw new Error(`Msearch failure: ${JSON.stringify(response.error)}`); + } else if (response.hits.hits.length > 0) { + return response.hits.hits; + } else { + return []; + } + }); } } diff --git a/packages/kbn-performance-testing-dataset-extractor/src/es_request.ts b/packages/kbn-performance-testing-dataset-extractor/src/es_request.ts deleted file mode 100644 index 5160d1cf1b0cc5..00000000000000 --- a/packages/kbn-performance-testing-dataset-extractor/src/es_request.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 { ESClient, SpanDocument } from './es_client'; -import { KibanaRequest } from './server_request'; - -const httpMethodRegExp = /(GET|POST|DELETE|HEAD|PUT|OPTIONS)/; -const httpPathRegExp = /(?<=GET|POST|DELETE|HEAD|PUT|OPTIONS).*/; - -interface Request { - id: string; - transactionId: string; - name: string; - action: string; - request: { - method?: string; - path?: string; - params?: string; - body?: JSON; - }; - date: string; - duration: number; -} - -interface Stream { - startTime: number; - endTime: number; - requests: Request[]; -} - -const strToJSON = (str: string): JSON | undefined => { - try { - return JSON.parse(str); - } catch (e) { - return; - } -}; - -const findFirstMatch = (regExp: RegExp, testString: string) => { - const found = regExp.exec(testString); - return found ? found[0] : undefined; -}; - -const parseQueryStatement = (statement: string): { params?: string; body?: JSON } => { - // github.com/elastic/apm-agent-nodejs/blob/5ba1b2609d18b12a64e1e559236717dd38d64a51/lib/instrumentation/elasticsearch-shared.js#L27-L29 - // Some ES endpoints support both query params and a body, statement string might contain both of it - const split = statement.split('\n\n'); - if (split.length === 2) { - return { params: split[0], body: strToJSON(split[1]) }; - } else { - const body = strToJSON(split[0]); - return body ? { body } : { params: split[0] }; - } -}; - -export const fetchRequests = async (esClient: ESClient, requests: KibanaRequest[]) => { - const esRequests = new Array(); - for (const request of requests) { - const transactionId = request.transaction.id; - const hits = await esClient.getSpans(transactionId); - const spans = hits - .map((hit) => hit!._source as SpanDocument) - .map((hit) => { - const query = hit?.span.db?.statement ? parseQueryStatement(hit?.span.db?.statement) : {}; - return { - id: hit.span.id, - transactionId: hit.transaction.id, - name: hit.span.name, - action: hit.span?.action, - request: { - method: findFirstMatch(httpMethodRegExp, hit.span.name), - path: findFirstMatch(httpPathRegExp, hit.span.name.replace(/\s+/g, '')), - params: query?.params, - body: query?.body, - }, - date: hit['@timestamp'], - duration: hit.span?.duration?.us, - }; - }) - // filter out requests without method, path and POST/PUT/DELETE without body - .filter( - (hit) => - hit && - hit.request?.method && - hit.request?.path && - (hit.request?.method === 'GET' || hit.request?.body) - ); - esRequests.push(...spans); - } - - return esRequests; -}; - -export const requestsToStreams = (requests: Request[]) => { - const sorted = requests.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); - const streams = new Map(); - - for (const request of sorted) { - const startTime = new Date(request.date).getTime(); - const endTime = new Date(request.date).getTime() + request.duration / 1000; - // searching if query starts before any existing stream ended - const match = Array.from(streams.keys()).filter((key) => { - const streamEndTime = streams.get(key)?.endTime; - return streamEndTime ? startTime < streamEndTime : false; - }); - const stream = streams.get(match[0]); - if (stream) { - // adding query to the existing stream - stream.requests.push(request); - // updating the stream endTime if needed - if (endTime > stream.endTime) { - stream.endTime = endTime; - } - // saving updated stream - streams.set(match[0], stream); - } else { - // add a new stream - streams.set(request.date, { - startTime, - endTime, - requests: [request], - }); - } - } - - const values = Array.from(streams.values()); - return values.map((stream) => { - return { - startTime: new Date(stream.startTime).toISOString(), - endTime: new Date(stream.endTime).toISOString(), - requests: stream.requests, - }; - }); -}; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/extractor.ts b/packages/kbn-performance-testing-dataset-extractor/src/extractor.ts index e0587af1637d8e..992c93b16922d1 100644 --- a/packages/kbn-performance-testing-dataset-extractor/src/extractor.ts +++ b/packages/kbn-performance-testing-dataset-extractor/src/extractor.ts @@ -13,38 +13,10 @@ import path from 'path'; import { ToolingLog } from '@kbn/tooling-log'; import { SearchHit } from '@elastic/elasticsearch/lib/api/types'; import { ESClient, Document, TransactionDocument } from './es_client'; -import { getRequests } from './server_request'; -import { fetchRequests, requestsToStreams } from './es_request'; - -const DATE_FORMAT = `YYYY-MM-DD'T'HH:mm:ss.SSS'Z'`; - -interface CLIParams { - param: { - journeyName: string; - scalabilitySetup: ScalabilitySetup; - buildId: string; - withoutStaticResources: boolean; - }; - client: { - baseURL: string; - username: string; - password: string; - }; - log: ToolingLog; -} - -interface InjectionStep { - action: string; - minUsersCount?: number; - maxUsersCount: number; - duration: string; -} - -export interface ScalabilitySetup { - warmup: InjectionStep[]; - test: InjectionStep[]; - maxDuration: string; -} +import { getESRequests, getKibanaRequests } from './request'; +import { requestsToStreams } from './stream'; +import { CLIParams, Request } from './types'; +import { DATE_FORMAT } from './constants'; const calculateTransactionTimeRage = (hit: SearchHit) => { const trSource = hit._source as Document; @@ -100,12 +72,13 @@ export const extractor = async ({ param, client, log }: CLIParams) => { const source = hits[0]!._source as TransactionDocument; const kibanaVersion = source.service.version; - const kibanaRequests = getRequests(hits, withoutStaticResources, log); - const esRequests = await fetchRequests(esClient, kibanaRequests); + const kibanaRequests = getKibanaRequests(hits, withoutStaticResources); + const esRequests = await getESRequests(esClient, kibanaRequests); log.info( `Found ${kibanaRequests.length} Kibana server and ${esRequests.length} Elasticsearch requests` ); - const streams = requestsToStreams(esRequests); + const esStreams = requestsToStreams(esRequests); + const kibanaStreams = requestsToStreams(kibanaRequests); const outputDir = path.resolve('target/scalability_traces'); const fileName = `${journeyName.replace(/ /g, '')}-${buildId}.json`; @@ -116,7 +89,7 @@ export const extractor = async ({ param, client, log }: CLIParams) => { journeyName, kibanaVersion, scalabilitySetup, - requests: kibanaRequests, + streams: kibanaStreams, }, path.resolve(outputDir, 'server'), fileName, @@ -128,7 +101,7 @@ export const extractor = async ({ param, client, log }: CLIParams) => { { journeyName, kibanaVersion, - streams: Array.from(streams.values()), + streams: esStreams, }, path.resolve(outputDir, 'es'), fileName, diff --git a/packages/kbn-performance-testing-dataset-extractor/src/request.ts b/packages/kbn-performance-testing-dataset-extractor/src/request.ts new file mode 100644 index 00000000000000..7c9efaf9357424 --- /dev/null +++ b/packages/kbn-performance-testing-dataset-extractor/src/request.ts @@ -0,0 +1,106 @@ +/* + * 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 { SearchHit } from '@elastic/elasticsearch/lib/api/types'; +import { ESClient, TransactionDocument, Headers, SpanDocument } from './es_client'; +import { Request } from './types'; + +const httpMethodRegExp = /(GET|POST|DELETE|HEAD|PUT|OPTIONS)/; +const httpPathRegExp = /(?<=GET|POST|DELETE|HEAD|PUT|OPTIONS).*/; +const staticResourcesRegExp = /\.(css|ico|js|json|jpeg|jpg|gif|png|svg|otf|ttf|woff|woff2)$/; + +const strToJSON = (str: string): JSON | undefined => { + try { + return JSON.parse(str); + } catch (e) { + return; + } +}; + +const findFirstMatch = (regExp: RegExp, testString: string) => { + const found = regExp.exec(testString); + return found ? found[0] : undefined; +}; + +const parseQueryStatement = (statement: string): { params?: string; body?: JSON } => { + // github.com/elastic/apm-agent-nodejs/blob/5ba1b2609d18b12a64e1e559236717dd38d64a51/lib/instrumentation/elasticsearch-shared.js#L27-L29 + // Some ES endpoints support both query params and a body, statement string might contain both of it + const split = statement.split('\n\n'); + if (split.length === 2) { + return { params: split[0], body: strToJSON(split[1]) }; + } else { + const body = strToJSON(split[0]); + return body ? { body } : { params: split[0] }; + } +}; + +const combineHeaderFieldValues = (headers: Headers): { [key: string]: string } => { + return Object.assign( + {}, + ...Object.keys(headers).map((key) => ({ [key]: headers[key].join(', ') })) + ); +}; + +export const getKibanaRequests = ( + hits: Array>, + withoutStaticResources: boolean +): Request[] => { + const data = hits + .map((hit) => hit!._source as TransactionDocument) + .map((hit) => { + const payload = hit.http.request?.body?.original; + return { + transactionId: hit.transaction.id, + name: hit.transaction.name, + date: hit['@timestamp'], + duration: hit.transaction.duration.us, + http: { + method: hit.http.request.method, + path: hit.url.path, + headers: combineHeaderFieldValues(hit.http.request.headers), + body: payload ? JSON.stringify(strToJSON(payload)) : undefined, + statusCode: hit.http.response.status_code, + }, + spanCount: hit.transaction.span_count.started, + }; + }); + + return withoutStaticResources + ? data.filter((item) => !staticResourcesRegExp.test(item.http.path)) + : data; +}; + +export const getESRequests = async (esClient: ESClient, requests: Request[]) => { + const esRequests = new Array(); + const transactionIds = requests + .filter((r) => r.spanCount && r?.spanCount > 0) + .map((r) => r.transactionId); + const hits = await esClient.getSpans(transactionIds); + for (const hit of hits.map((i) => i!._source as SpanDocument)) { + const query = hit?.span?.db?.statement ? parseQueryStatement(hit?.span?.db?.statement) : {}; + const method = findFirstMatch(httpMethodRegExp, hit.span.name); + const path = findFirstMatch(httpPathRegExp, hit.span.name.replace(/\s+/g, '')); + // filter out requests without method, path and POST/PUT/DELETE without body + if (method && path && (method === 'GET' || query?.body)) { + esRequests.push({ + transactionId: hit.transaction.id, + spanId: hit.span.id, + name: hit.span.name, + date: hit['@timestamp'], + duration: hit.span?.duration?.us, + http: { + method, + path, + params: query?.params, + body: query?.body, + }, + }); + } + } + return esRequests; +}; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/server_request.ts b/packages/kbn-performance-testing-dataset-extractor/src/server_request.ts deleted file mode 100644 index dd553b83848c85..00000000000000 --- a/packages/kbn-performance-testing-dataset-extractor/src/server_request.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 { SearchHit } from '@elastic/elasticsearch/lib/api/types'; -import { ToolingLog } from '@kbn/tooling-log'; -import { TransactionDocument, Headers } from './es_client'; - -const staticResourcesRegExp = /\.(css|ico|js|json|jpeg|jpg|gif|png|otf|ttf|woff|woff2)$/; - -export interface KibanaRequest { - traceId: string; - parentId?: string; - processor: string; - environment: string; - request: { - timestamp: string; - method: string; - path: string; - headers: { [key: string]: string }; - body?: string; - statusCode: number; - }; - transaction: { - id: string; - name: string; - type: string; - }; -} - -const parsePayload = (payload: string, traceId: string, log: ToolingLog): string | undefined => { - let body; - try { - body = JSON.parse(payload); - } catch (error) { - log.error(`Failed to parse payload - trace_id: '${traceId}'`); - } - return body; -}; - -const combineHeaderFieldValues = (headers: Headers): { [key: string]: string } => { - return Object.assign( - {}, - ...Object.keys(headers).map((key) => ({ [key]: headers[key].join(', ') })) - ); -}; - -export const getRequests = ( - hits: Array>, - withoutStaticResources: boolean, - log: ToolingLog -): KibanaRequest[] => { - const data = hits - .map((hit) => hit!._source as TransactionDocument) - .map((hit) => { - const payload = hit.http.request?.body?.original; - return { - traceId: hit.trace.id, - parentId: hit?.parent?.id, - processor: hit.processor, - environment: hit.service.environment, - request: { - timestamp: hit['@timestamp'], - method: hit.http.request.method, - path: hit.url.path, - headers: combineHeaderFieldValues(hit.http.request.headers), - body: payload ? JSON.stringify(parsePayload(payload, hit.trace.id, log)) : undefined, - statusCode: hit.http.response.status_code, - }, - transaction: { - id: hit.transaction.id, - name: hit.transaction.name, - type: hit.transaction.type, - }, - }; - }); - - return withoutStaticResources - ? data.filter((item) => !staticResourcesRegExp.test(item.request.path)) - : data; -}; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/stream.test.ts b/packages/kbn-performance-testing-dataset-extractor/src/stream.test.ts new file mode 100644 index 00000000000000..51fdde19358a31 --- /dev/null +++ b/packages/kbn-performance-testing-dataset-extractor/src/stream.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { requestsToStreams, getTime } from './stream'; + +test('requests to stream', () => { + const requests = new Array( + { + transactionId: 'a8ba23df51ebb853', + spanId: '85c8de731132bea2', + name: 'Elasticsearch: GET /.kibana_8.5.0/_doc/config%3A8.5.0', + date: '2022-08-08T17:43:58.647Z', + duration: 398, + http: { + method: 'GET', + path: '/.kibana_8.5.0/_doc/config%3A8.5.0', + }, + }, + { + transactionId: '15ba53df5t9bb165', + spanId: '15v8de5341v2neat', + name: 'Elasticsearch: GET /.kibana_8.5.0/_doc/config%3A8.5.0', + date: '2022-08-08T17:43:58.641Z', + duration: 1988, + http: { + method: 'GET', + path: '/.kibana_8.5.0/_doc/config%3A8.5.0', + }, + }, + { + transactionId: '90d8037a799382ac', + spanId: 'b819755f297188d9', + name: 'Elasticsearch: GET /_security/_authenticate', + date: '2022-08-08T17:43:58.649Z', + duration: 1002, + http: { + method: 'GET', + path: '/_security/_authenticate', + }, + }, + { + transactionId: '1381d9ed5af967f9', + spanId: '690d11ebfefd06ad', + name: 'Elasticsearch: GET /.kibana_8.5.0/_doc/config%3A8.5.0', + date: '2022-08-08T17:43:58.648Z', + duration: 2400, + http: { + method: 'GET', + path: '/.kibana_8.5.0/_doc/config%3A8.5.0', + }, + }, + { + transactionId: '96174ca1fbd14763', + spanId: '4c81025cb74c9cd6', + name: 'Elasticsearch: GET /_security/_authenticate', + date: '2022-08-08T17:43:58.640Z', + duration: 4166, + http: { + method: 'GET', + path: '/_security/_authenticate', + }, + } + ); + + const streams = requestsToStreams(requests); + const sorted = requests.sort((a, b) => getTime(a.date) - getTime(b.date)); + + expect(streams.length).toBe(3); + expect(streams[0].requests.length).toBe(2); + expect(streams[0].startTime).toBe(streams[0].requests[0].date); + expect(streams[0].startTime).toBe(sorted[0].date); + expect(streams[1].requests.length).toBe(1); + expect(getTime(streams[1].startTime)).toBeGreaterThan(getTime(streams[0].endTime)); + expect(streams[2].requests.length).toBe(2); +}); diff --git a/packages/kbn-performance-testing-dataset-extractor/src/stream.ts b/packages/kbn-performance-testing-dataset-extractor/src/stream.ts new file mode 100644 index 00000000000000..48f7dfe2d08c34 --- /dev/null +++ b/packages/kbn-performance-testing-dataset-extractor/src/stream.ts @@ -0,0 +1,57 @@ +/* + * 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 { Request, Stream } from './types'; + +export const getTime = (date: string) => new Date(date).getTime(); + +/** + * Combines concurrent requests into the streams and returns it as Array + * @param requests requests array + */ +export const requestsToStreams = (requests: T[]) => { + const sorted = requests.sort((a, b) => getTime(a.date) - getTime(b.date)); + const streams = new Map>(); + + for (const request of sorted) { + const startTime = getTime(request.date) * 1000; + const endTime = getTime(request.date) * 1000 + request.duration; + // Checking if request starts before any existing stream ended + const match = Array.from(streams.keys()).filter((key) => { + const streamEndTimestamp = streams.get(key)?.endTime; + return streamEndTimestamp ? startTime < streamEndTimestamp : false; + }); + const stream = streams.get(match[0]); + if (stream) { + // Adding request to the existing stream + stream.requests.push(request); + // Updating the stream end time if needed + if (endTime > stream.endTime) { + stream.endTime = endTime; + } + // Saving the updated stream + streams.set(match[0], stream); + } else { + // Otherwise adding a new stream + streams.set(request.date, { + startTime, + endTime, + requests: [request], + }); + } + } + + const values = Array.from(streams.values()); + return values.map((stream) => { + return { + startTime: new Date(stream.startTime / 1000).toISOString(), + endTime: new Date(stream.endTime / 1000).toISOString(), + requests: stream.requests, + }; + }); +}; diff --git a/packages/kbn-performance-testing-dataset-extractor/src/types.ts b/packages/kbn-performance-testing-dataset-extractor/src/types.ts new file mode 100644 index 00000000000000..1cd51f3388a7c0 --- /dev/null +++ b/packages/kbn-performance-testing-dataset-extractor/src/types.ts @@ -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 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 { ToolingLog } from '@kbn/tooling-log'; + +export interface Request { + transactionId: string; + spanId?: string; + name: string; + date: string; + duration: number; + http: { + method: string; + path: string; + headers?: { [key: string]: string }; + params?: string; + body?: JSON | string; + }; + spanCount?: number; +} + +export interface Stream { + startTime: number; + endTime: number; + requests: T[]; +} + +export interface InjectionStep { + action: string; + minUsersCount?: number; + maxUsersCount: number; + duration: string; +} + +export interface ScalabilitySetup { + warmup: InjectionStep[]; + test: InjectionStep[]; + maxDuration: string; +} + +export interface CLIParams { + param: { + journeyName: string; + scalabilitySetup: ScalabilitySetup; + buildId: string; + withoutStaticResources: boolean; + }; + client: { + baseURL: string; + username: string; + password: string; + }; + log: ToolingLog; +} From 785532eab659a5a2393aec10e737537492049aba Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Thu, 11 Aug 2022 14:10:05 +0200 Subject: [PATCH 12/59] [SecuritySolution] Move related alerts by process ancestry behind platinum subscription (#138419) * feat: show an upsell for users without platinum license * test: add license-related tests * feat: re-add the feature flag * nit: use EuiLink * fix: check for length as well * chore: move data check to helper This reduced the overall complexity of the module, which made the eslint complexity exception obsolete * tests: * tests: fix tests * tests: fix integration tests --- .../event_details/insights/helpers.ts | 21 ++++ .../insights/insight_accordion.tsx | 5 +- .../event_details/insights/insights.test.tsx | 96 +++++++++++++++++++ .../event_details/insights/insights.tsx | 42 ++++---- .../related_alerts_by_process_ancestry.tsx | 4 +- .../insights/related_alerts_by_session.tsx | 4 +- .../insights/related_alerts_upsell.tsx | 48 ++++++++++ .../event_details/insights/translations.ts | 7 ++ .../server/endpoint/routes/resolver.ts | 4 +- .../endpoint/routes/resolver/tree/handler.ts | 20 +++- .../services/feature_usage/service.ts | 1 + 11 files changed, 227 insertions(+), 25 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/common/components/event_details/insights/helpers.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/helpers.ts b/x-pack/plugins/security_solution/public/common/components/event_details/insights/helpers.ts new file mode 100644 index 00000000000000..8864e99bd1ed3a --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/helpers.ts @@ -0,0 +1,21 @@ +/* + * 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 type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; + +type TimelineEventsDetailsItemWithValues = TimelineEventsDetailsItem & { + values: string[]; +}; + +/** + * Checks if the `item` has a non-empty `values` array + */ +export function hasData( + item?: TimelineEventsDetailsItem +): item is TimelineEventsDetailsItemWithValues { + return Boolean(item && item.values && item.values.length); +} diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insight_accordion.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insight_accordion.tsx index 67635b52fff3f5..b0ee6a53d71f76 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insight_accordion.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insight_accordion.tsx @@ -25,6 +25,7 @@ interface Props { state: InsightAccordionState; text: string; renderContent: () => ReactNode; + extraAction?: EuiAccordionProps['extraAction']; onToggle?: EuiAccordionProps['onToggle']; } @@ -33,7 +34,7 @@ interface Props { * It wraps logic and custom styling around the loading, error and success states of an insight section. */ export const InsightAccordion = React.memo( - ({ prefix, state, text, renderContent, onToggle = noop }) => { + ({ prefix, state, text, renderContent, onToggle = noop, extraAction }) => { const accordionId = useGeneratedHtmlId({ prefix }); switch (state) { @@ -54,6 +55,7 @@ export const InsightAccordion = React.memo( } onToggle={onToggle} + extraAction={extraAction} /> ); case 'success': @@ -64,6 +66,7 @@ export const InsightAccordion = React.memo( buttonContent={text} onToggle={onToggle} paddingSize="l" + extraAction={extraAction} > {renderContent()} diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx index 7c9ee3200dcab6..747b2ec939f715 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.test.tsx @@ -10,8 +10,11 @@ import React from 'react'; import { TestProviders } from '../../../mock'; +import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; import { useKibana as mockUseKibana } from '../../../lib/kibana/__mocks__'; import { useGetUserCasesPermissions } from '../../../lib/kibana'; +import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; +import { licenseService } from '../../../hooks/use_license'; import { noCasesPermissions, readCasesPermissions } from '../../../../cases_test_utils'; import { Insights } from './insights'; import * as i18n from './translations'; @@ -39,6 +42,46 @@ jest.mock('../../../lib/kibana', () => { }); const mockUseGetUserCasesPermissions = useGetUserCasesPermissions as jest.Mock; +jest.mock('../../../hooks/use_license', () => { + const licenseServiceInstance = { + isPlatinumPlus: jest.fn(), + isEnterprise: jest.fn(() => true), + }; + return { + licenseService: licenseServiceInstance, + useLicense: () => { + return licenseServiceInstance; + }, + }; +}); +const licenseServiceMock = licenseService as jest.Mocked; + +jest.mock('../../../hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(true), +})); +const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; + +const data: TimelineEventsDetailsItem[] = [ + { + category: 'process', + field: 'process.entity_id', + isObjectArray: false, + values: ['32082y34028u34'], + }, + { + category: 'kibana', + field: 'kibana.alert.ancestors.id', + isObjectArray: false, + values: ['woeurhw98rhwr'], + }, + { + category: 'kibana', + field: 'kibana.alert.rule.parameters.index', + isObjectArray: false, + values: ['fakeindex'], + }, +]; + describe('Insights', () => { beforeEach(() => { mockUseGetUserCasesPermissions.mockReturnValue(noCasesPermissions()); @@ -77,4 +120,57 @@ describe('Insights', () => { }) ).toBeInTheDocument(); }); + + describe('with feature flag enabled', () => { + describe('with platinum license', () => { + it('should show insights for related alerts by process ancestry', () => { + licenseServiceMock.isPlatinumPlus.mockReturnValue(true); + + render( + + + + ); + + expect(screen.getByTestId('related-alerts-by-ancestry')).toBeInTheDocument(); + expect( + screen.queryByRole('link', { name: new RegExp(i18n.ALERT_UPSELL) }) + ).not.toBeInTheDocument(); + }); + }); + + describe('without platinum license', () => { + it('should show an upsell for related alerts by process ancestry', () => { + licenseServiceMock.isPlatinumPlus.mockReturnValue(false); + + render( + + + + ); + + expect( + screen.getByRole('link', { name: new RegExp(i18n.ALERT_UPSELL) }) + ).toBeInTheDocument(); + expect(screen.queryByTestId('related-alerts-by-ancestry')).not.toBeInTheDocument(); + }); + }); + }); + + describe('with feature flag disabled', () => { + it('should not render neither the upsell, nor the insights for alerts by process ancestry', () => { + useIsExperimentalFeatureEnabledMock.mockReturnValue(false); + + render( + + + + ); + + expect(screen.queryByTestId('related-alerts-by-ancestry')).not.toBeInTheDocument(); + expect( + screen.queryByRole('link', { name: new RegExp(i18n.ALERT_UPSELL) }) + ).not.toBeInTheDocument(); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx index e6ee74185d4e73..358b2d8833a635 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/insights.tsx @@ -13,12 +13,15 @@ import * as i18n from './translations'; import type { BrowserFields } from '../../../containers/source'; import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; +import { hasData } from './helpers'; import { useGetUserCasesPermissions } from '../../../lib/kibana'; import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; +import { useLicense } from '../../../hooks/use_license'; import { RelatedAlertsByProcessAncestry } from './related_alerts_by_process_ancestry'; import { RelatedCases } from './related_cases'; import { RelatedAlertsBySourceEvent } from './related_alerts_by_source_event'; import { RelatedAlertsBySession } from './related_alerts_by_session'; +import { RelatedAlertsUpsell } from './related_alerts_upsell'; interface Props { browserFields: BrowserFields; @@ -36,6 +39,7 @@ export const Insights = React.memo( const isRelatedAlertsByProcessAncestryEnabled = useIsExperimentalFeatureEnabled( 'insightsRelatedAlertsByProcessAncestry' ); + const hasAtLeastPlatinum = useLicense().isPlatinumPlus(); const processEntityField = find({ category: 'process', field: 'process.entity_id' }, data); const originalDocumentId = find( { category: 'kibana', field: 'kibana.alert.ancestors.id' }, @@ -45,20 +49,20 @@ export const Insights = React.memo( { category: 'kibana', field: 'kibana.alert.rule.parameters.index' }, data ); - const hasProcessEntityInfo = - isRelatedAlertsByProcessAncestryEnabled && processEntityField && processEntityField.values; + const hasProcessEntityInfo = hasData(processEntityField); const processSessionField = find( { category: 'process', field: 'process.entry_leader.entity_id' }, data ); - const hasProcessSessionInfo = processSessionField && processSessionField.values; + const hasProcessSessionInfo = + isRelatedAlertsByProcessAncestryEnabled && hasData(processSessionField); const sourceEventField = find( { category: 'kibana', field: 'kibana.alert.original_event.id' }, data ); - const hasSourceEventInfo = sourceEventField && sourceEventField.values; + const hasSourceEventInfo = hasData(sourceEventField); const userCasesPermissions = useGetUserCasesPermissions(); const hasCasesReadPermissions = userCasesPermissions.read; @@ -74,8 +78,7 @@ export const Insights = React.memo( const canShowAncestryInsight = isRelatedAlertsByProcessAncestryEnabled && - processEntityField && - processEntityField.values && + hasProcessEntityInfo && originalDocumentId && originalDocumentIndex; @@ -122,17 +125,22 @@ export const Insights = React.memo( )} - {canShowAncestryInsight && ( - - - - )} + {canShowAncestryInsight && + (hasAtLeastPlatinum ? ( + + + + ) : ( + + + + ))} ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_process_ancestry.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_process_ancestry.tsx index 0171595fcc3b01..bea416ff51ec6d 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_process_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_process_ancestry.tsx @@ -6,7 +6,7 @@ */ import React, { useMemo, useCallback, useEffect, useState } from 'react'; -import { EuiSpacer, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiBetaBadge, EuiSpacer, EuiLoadingSpinner } from '@elastic/eui'; import type { DataProvider } from '../../../../../common/types'; import { TimelineId } from '../../../../../common/types/timeline'; @@ -23,6 +23,7 @@ import { PROCESS_ANCESTRY_EMPTY, PROCESS_ANCESTRY_ERROR, } from './translations'; +import { BETA } from '../../../translations'; interface Props { data: TimelineEventsDetailsItem; @@ -112,6 +113,7 @@ export const RelatedAlertsByProcessAncestry = React.memo( } renderContent={renderContent} onToggle={onToggle} + extraAction={} /> ); } diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_session.tsx index 8b0b308829c3d9..49dbc7ec674caa 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_by_session.tsx @@ -6,7 +6,7 @@ */ import React, { useCallback } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiBetaBadge, EuiSpacer } from '@elastic/eui'; import type { BrowserFields } from '../../../containers/source'; import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; @@ -19,6 +19,7 @@ import { SimpleAlertTable } from './simple_alert_table'; import { getEnrichedFieldInfo } from '../helpers'; import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../../../detections/components/alerts_table/translations'; import { SESSION_LOADING, SESSION_EMPTY, SESSION_ERROR, SESSION_COUNT } from './translations'; +import { BETA } from '../../../translations'; interface Props { browserFields: BrowserFields; @@ -99,6 +100,7 @@ export const RelatedAlertsBySession = React.memo( state={state} text={getTextFromState(state, count)} renderContent={renderContent} + extraAction={} /> ); } diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx new file mode 100644 index 00000000000000..37ac07e3c03d02 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/related_alerts_upsell.tsx @@ -0,0 +1,48 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiLink, EuiIcon, EuiText } from '@elastic/eui'; + +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { ALERT_UPSELL } from './translations'; + +const UpsellContainer = euiStyled.div` + border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade}; + padding: 12px; + border-radius: 6px; +`; + +const StyledIcon = euiStyled(EuiIcon)` + margin-right: 10px; +`; + +export const RelatedAlertsUpsell = React.memo(() => { + return ( + + + + + + + + + {ALERT_UPSELL} + + + + + + ); +}); + +RelatedAlertsUpsell.displayName = 'RelatedAlertsUpsell'; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/insights/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/insights/translations.ts index e77bbeb60ae8e1..e839003e1f7f9d 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/insights/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/insights/translations.ts @@ -135,3 +135,10 @@ export const SIMPLE_ALERT_TABLE_LIMITED = i18n.translate( defaultMessage: 'Showing only the latest 10 alerts. View the rest of alerts in timeline.', } ); + +export const ALERT_UPSELL = i18n.translate( + 'xpack.securitySolution.alertDetails.overview.insights.alertUpsellTitle', + { + defaultMessage: 'Get more insights with a subscription', + } +); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts index b4fcee14a1804d..44f897d8883cc7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver.ts @@ -23,14 +23,14 @@ export const registerResolverRoutes = async ( startServices: StartServicesAccessor, config: ConfigType ) => { - const [, { ruleRegistry }] = await startServices(); + const [, { ruleRegistry, licensing }] = await startServices(); router.post( { path: '/api/endpoint/resolver/tree', validate: validateTree, options: { authRequired: true }, }, - handleTree(ruleRegistry, config) + handleTree(ruleRegistry, config, licensing) ); router.post( diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts index 8084dd26fc9ec3..b4931da5ae16d3 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/resolver/tree/handler.ts @@ -5,23 +5,37 @@ * 2.0. */ +import { firstValueFrom } from 'rxjs'; + import type { RequestHandler } from '@kbn/core/server'; import type { TypeOf } from '@kbn/config-schema'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; -import type { validateTree } from '../../../../../common/endpoint/schema/resolver'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { ConfigType } from '../../../../config'; + +import type { validateTree } from '../../../../../common/endpoint/schema/resolver'; +import { featureUsageService } from '../../../services/feature_usage'; import { Fetcher } from './utils/fetch'; export function handleTree( ruleRegistry: RuleRegistryPluginStartContract, - config: ConfigType + config: ConfigType, + licensing: LicensingPluginStart ): RequestHandler> { return async (context, req, res) => { const client = (await context.core).elasticsearch.client; const { experimentalFeatures: { insightsRelatedAlertsByProcessAncestry }, } = config; - const alertsClient = insightsRelatedAlertsByProcessAncestry + const license = await firstValueFrom(licensing.license$); + const hasAccessToInsightsRelatedByProcessAncestry = + insightsRelatedAlertsByProcessAncestry && license.hasAtLeast('platinum'); + + if (hasAccessToInsightsRelatedByProcessAncestry) { + featureUsageService.notifyUsage('ALERTS_BY_PROCESS_ANCESTRY'); + } + + const alertsClient = hasAccessToInsightsRelatedByProcessAncestry ? await ruleRegistry.getRacClientWithRequest(req) : undefined; const fetcher = new Fetcher(client, alertsClient); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts index 7b9edee253c873..46c75cd6f73ebf 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/feature_usage/service.ts @@ -21,6 +21,7 @@ const FEATURES = { KILL_PROCESS: 'Kill process', SUSPEND_PROCESS: 'Suspend process', RUNNING_PROCESSES: 'Get running processes', + ALERTS_BY_PROCESS_ANCESTRY: 'Get related alerts by process ancestry', } as const; export type FeatureKeys = keyof typeof FEATURES; From 7834105ae351fb342fda2230385d9a678df583da Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 11 Aug 2022 08:12:30 -0400 Subject: [PATCH 13/59] skip failing test suite (#86544) --- .../security_and_spaces/apis/copy_to_space.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space.ts b/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space.ts index 48b8b0e114af21..81018230f4e07e 100644 --- a/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space.ts +++ b/x-pack/test/spaces_api_integration/security_and_spaces/apis/copy_to_space.ts @@ -29,7 +29,8 @@ export default function copyToSpaceSpacesAndSecuritySuite({ getService }: FtrPro createMultiNamespaceTestCases, } = copyToSpaceTestSuiteFactory(es, esArchiver, supertestWithoutAuth); - describe('copy to spaces', () => { + // Failing: See https://github.com/elastic/kibana/issues/86544 + describe.skip('copy to spaces', () => { [ { spaceId: SPACES.DEFAULT.spaceId, From bc1fe28b2353024b3e1ba9d6e29fd810a9e54479 Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Thu, 11 Aug 2022 14:24:25 +0200 Subject: [PATCH 14/59] [Enterprise Search] Update recheck copy (#138483) --- .../components/search_index/index_view_logic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.ts index 1be7c2e9cf58d3..319209c67fda74 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_view_logic.ts @@ -148,7 +148,7 @@ export const IndexViewLogic = kea Date: Thu, 11 Aug 2022 08:38:51 -0400 Subject: [PATCH 15/59] [Fleet] Delete one package policy API (#138560) --- .../plugins/fleet/common/openapi/bundled.json | 83 ++-- .../plugins/fleet/common/openapi/bundled.yaml | 55 ++- .../package_policies@{package_policy_id}.yaml | 26 ++ .../common/types/rest_spec/package_policy.ts | 5 + .../server/routes/package_policy/handlers.ts | 48 +++ .../server/routes/package_policy/index.ts | 13 + .../server/types/rest_spec/package_policy.ts | 9 + .../apis/package_policy/delete.ts | 393 ++++++++++++------ 8 files changed, 463 insertions(+), 169 deletions(-) diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index 357ceb3192e6f6..f7d5054f532245 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -2961,6 +2961,48 @@ "$ref": "#/components/parameters/kbn_xsrf" } ] + }, + "delete": { + "summary": "Package policy - Delete", + "tags": [], + "operationId": "delete-package-policy", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string" + }, + "name": "packagePolicyId", + "in": "path", + "required": true + }, + { + "schema": { + "type": "boolean" + }, + "name": "force", + "in": "query" + } + ] } }, "/outputs": { @@ -4306,6 +4348,10 @@ "description": "list of agent IDs" } ] + }, + "force": { + "type": "boolean", + "description": "Force upgrade, skipping validation (should be used with caution)" } }, "required": [ @@ -4315,32 +4361,21 @@ }, "upgrade_agent": { "title": "Upgrade agent", - "oneOf": [ - { - "type": "object", - "properties": { - "version": { - "type": "string" - } - }, - "required": [ - "version" - ] + "type": "object", + "properties": { + "version": { + "type": "string" }, - { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "source_uri": { - "type": "string" - } - }, - "required": [ - "version" - ] + "source_uri": { + "type": "string" + }, + "force": { + "type": "boolean", + "description": "Force upgrade, skipping validation (should be used with caution)" } + }, + "required": [ + "version" ] }, "agent_action": { diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index b902f130b2e183..60827666ca5e87 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -1820,6 +1820,32 @@ paths: - sucess parameters: - $ref: '#/components/parameters/kbn_xsrf' + delete: + summary: Package policy - Delete + tags: [] + operationId: delete-package-policy + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + id: + type: string + required: + - id + parameters: + - schema: + type: string + name: packagePolicyId + in: path + required: true + - schema: + type: boolean + name: force + in: query /outputs: get: summary: Outputs @@ -2716,26 +2742,25 @@ components: items: type: string description: list of agent IDs + force: + type: boolean + description: Force upgrade, skipping validation (should be used with caution) required: - agents - version upgrade_agent: title: Upgrade agent - oneOf: - - type: object - properties: - version: - type: string - required: - - version - - type: object - properties: - version: - type: string - source_uri: - type: string - required: - - version + type: object + properties: + version: + type: string + source_uri: + type: string + force: + type: boolean + description: Force upgrade, skipping validation (should be used with caution) + required: + - version agent_action: title: Agent action oneOf: diff --git a/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml b/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml index 7bd20ab17fdd3e..8dda212c409eb1 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml @@ -45,3 +45,29 @@ put: - sucess parameters: - $ref: ../components/headers/kbn_xsrf.yaml +delete: + summary: Package policy - Delete + tags: [] + operationId: delete-package-policy + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + id: + type: string + required: + - id + parameters: + - schema: + type: string + name: packagePolicyId + in: path + required: true + - schema: + type: boolean + name: force + in: query diff --git a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts index aa39266b4f7a9c..260c8ebc8142f2 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts @@ -59,6 +59,11 @@ export type DeletePackagePoliciesResponse = Array<{ success: boolean; package?: PackagePolicyPackage; policy_id?: string; + // Support generic errors + statusCode?: number; + body?: { + message: string; + }; }>; export interface UpgradePackagePolicyBaseResponse { diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts index a94b957c98cce4..8ecbd11ec59866 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts @@ -24,6 +24,7 @@ import type { DryRunPackagePoliciesRequestSchema, FleetRequestHandler, PackagePolicy, + DeleteOnePackagePolicyRequestSchema, } from '../../types'; import type { CreatePackagePolicyResponse, @@ -290,6 +291,53 @@ export const deletePackagePolicyHandler: RequestHandler< } }; +export const deleteOnePackagePolicyHandler: RequestHandler< + TypeOf, + TypeOf, + unknown +> = async (context, request, response) => { + const coreContext = await context.core; + const soClient = coreContext.savedObjects.client; + const esClient = coreContext.elasticsearch.client.asInternalUser; + const user = appContextService.getSecurity()?.authc.getCurrentUser(request) || undefined; + try { + const res = await packagePolicyService.delete( + soClient, + esClient, + [request.params.packagePolicyId], + { user, force: request.query.force, skipUnassignFromAgentPolicies: request.query.force } + ); + + if ( + res[0] && + res[0].success === false && + res[0].statusCode !== 404 // ignore 404 to allow that call to be idempotent + ) { + return response.customError({ + statusCode: res[0].statusCode ?? 500, + body: res[0].body, + }); + } + try { + await packagePolicyService.runExternalCallbacks( + 'postPackagePolicyDelete', + res, + context, + request + ); + } catch (error) { + const logger = appContextService.getLogger(); + logger.error(`An error occurred executing external callback: ${error}`); + logger.error(error); + } + return response.ok({ + body: { id: request.params.packagePolicyId }, + }); + } catch (error) { + return defaultIngestErrorHandler({ error, response }); + } +}; + export const upgradePackagePolicyHandler: RequestHandler< unknown, unknown, diff --git a/x-pack/plugins/fleet/server/routes/package_policy/index.ts b/x-pack/plugins/fleet/server/routes/package_policy/index.ts index 2b2ae190b80bba..cf52b740245f85 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/index.ts @@ -14,6 +14,7 @@ import { DeletePackagePoliciesRequestSchema, UpgradePackagePoliciesRequestSchema, DryRunPackagePoliciesRequestSchema, + DeleteOnePackagePolicyRequestSchema, } from '../../types'; import type { FleetAuthzRouter } from '../security'; @@ -26,6 +27,7 @@ import { upgradePackagePolicyHandler, dryRunUpgradePackagePolicyHandler, getOrphanedPackagePolicies, + deleteOnePackagePolicyHandler, } from './handlers'; export const registerRoutes = (router: FleetAuthzRouter) => { @@ -100,6 +102,17 @@ export const registerRoutes = (router: FleetAuthzRouter) => { deletePackagePolicyHandler ); + router.delete( + { + path: PACKAGE_POLICY_API_ROUTES.INFO_PATTERN, + validate: DeleteOnePackagePolicyRequestSchema, + fleetAuthz: { + integrations: { writeIntegrationPolicies: true }, + }, + }, + deleteOnePackagePolicyHandler + ); + // Upgrade router.post( { diff --git a/x-pack/plugins/fleet/server/types/rest_spec/package_policy.ts b/x-pack/plugins/fleet/server/types/rest_spec/package_policy.ts index 7f54b9c742d081..b085060286d05a 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/package_policy.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/package_policy.ts @@ -40,6 +40,15 @@ export const DeletePackagePoliciesRequestSchema = { }), }; +export const DeleteOnePackagePolicyRequestSchema = { + params: schema.object({ + packagePolicyId: schema.string(), + }), + query: schema.object({ + force: schema.maybe(schema.boolean()), + }), +}; + export const UpgradePackagePoliciesRequestSchema = { body: schema.object({ packagePolicyIds: schema.arrayOf(schema.string()), diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts b/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts index 1f7377ba189ba8..e95fbc9ad3dfd4 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/delete.ts @@ -12,143 +12,276 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); - // use function () {} and not () => {} here - // because `this` has to point to the Mocha context - // see https://mochajs.org/#arrow-functions - - describe('Package Policy - delete', async function () { + describe('Package Policy - delete', () => { skipIfNoDockerRegistry(providerContext); - let agentPolicy: any; - let packagePolicy: any; - before(async () => { - await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); - await getService('esArchiver').load( - 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' - ); - }); - before(async function () { - let agentPolicyResponse = await supertest - .post(`/api/fleet/agent_policies`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Test policy', - namespace: 'default', - is_managed: false, - }); - - // if one already exists, re-use that - if (agentPolicyResponse.body.statusCode === 409) { - const errorRegex = /^agent policy \'(?[\w,\-]+)\' already exists/i; - const result = errorRegex.exec(agentPolicyResponse.body.message); - if (result?.groups?.id) { - agentPolicyResponse = await supertest - .put(`/api/fleet/agent_policies/${result.groups.id}`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'Test policy', - namespace: 'default', - is_managed: false, - force: true, - }); + describe('Delete one', () => { + let agentPolicy: any; + let packagePolicy: any; + before(async () => { + await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await getService('esArchiver').load( + 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' + ); + }); + beforeEach(async () => { + let agentPolicyResponse = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: false, + }); + + // if one already exists, re-use that + if (agentPolicyResponse.body.statusCode === 409) { + const errorRegex = /^agent policy \'(?[\w,\-]+)\' already exists/i; + const result = errorRegex.exec(agentPolicyResponse.body.message); + if (result?.groups?.id) { + agentPolicyResponse = await supertest + .put(`/api/fleet/agent_policies/${result.groups.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: false, + force: true, + }); + } } - } - agentPolicy = agentPolicyResponse.body.item; - - const { body: packagePolicyResponse } = await supertest - .post(`/api/fleet/package_policies`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: 'filetest-1', - description: '', - namespace: 'default', - policy_id: agentPolicy.id, - enabled: true, - output_id: '', - inputs: [], - package: { - name: 'filetest', - title: 'For File Tests', - version: '0.1.0', - }, - }); - packagePolicy = packagePolicyResponse.item; - }); + agentPolicy = agentPolicyResponse.body.item; - after(async function () { - await supertest - .post(`/api/fleet/agent_policies/delete`) - .set('kbn-xsrf', 'xxxx') - .send({ agentPolicyId: agentPolicy.id }); + const { body: packagePolicyResponse } = await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + id: 'filetest-1', + name: 'filetest-1', + description: '', + namespace: 'default', + policy_id: agentPolicy.id, + enabled: true, + output_id: '', + inputs: [], + package: { + name: 'filetest', + title: 'For File Tests', + version: '0.1.0', + }, + }); - await supertest - .post(`/api/fleet/package_policies/delete`) - .set('kbn-xsrf', 'xxxx') - .send({ force: true, packagePolicyIds: [packagePolicy.id] }); - }); - after(async () => { - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); - await getService('esArchiver').unload( - 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' - ); - }); + packagePolicy = packagePolicyResponse.item; + }); + + afterEach(async () => { + await supertest + .post(`/api/fleet/agent_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ agentPolicyId: agentPolicy.id }); + + await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true, packagePolicyIds: [packagePolicy.id] }); + }); + after(async () => { + await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await getService('esArchiver').unload( + 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' + ); + }); + + it('should fail on hosted agent policies', async () => { + // update existing policy to hosted + await supertest + .put(`/api/fleet/agent_policies/${agentPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: agentPolicy.name, + namespace: agentPolicy.namespace, + is_managed: true, + }) + .expect(200); + + // try to delete + const { body: result } = await supertest + .delete(`/api/fleet/package_policies/${packagePolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .expect(400); + + expect(result.message).to.contain('Cannot remove integrations of hosted agent policy'); + + // same, but with force + await supertest + .delete(`/api/fleet/package_policies/${packagePolicy.id}?force=true`) + .set('kbn-xsrf', 'xxxx') + .expect(200); + + // revert existing policy to regular + await supertest + .put(`/api/fleet/agent_policies/${agentPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: agentPolicy.name, + namespace: agentPolicy.namespace, + is_managed: false, + force: true, + }) + .expect(200); + }); - it('should fail on hosted agent policies', async function () { - // update existing policy to hosted - await supertest - .put(`/api/fleet/agent_policies/${agentPolicy.id}`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: agentPolicy.name, - namespace: agentPolicy.namespace, - is_managed: true, - }) - .expect(200); - - // try to delete - const { body: results } = await supertest - .post(`/api/fleet/package_policies/delete`) - .set('kbn-xsrf', 'xxxx') - .send({ packagePolicyIds: [packagePolicy.id] }) - .expect(200); - - // delete always succeeds (returns 200) with Array<{success: boolean}> - expect(Array.isArray(results)); - expect(results.length).to.be(1); - expect(results[0].success).to.be(false); - expect(results[0].body.message).to.contain( - 'Cannot remove integrations of hosted agent policy' - ); - - // same, but with force - const { body: resultsWithForce } = await supertest - .post(`/api/fleet/package_policies/delete`) - .set('kbn-xsrf', 'xxxx') - .send({ force: true, packagePolicyIds: [packagePolicy.id] }) - .expect(200); - - // delete always succeeds (returns 200) with Array<{success: boolean}> - expect(Array.isArray(resultsWithForce)); - expect(resultsWithForce.length).to.be(1); - expect(resultsWithForce[0].success).to.be(true); - - // revert existing policy to regular - await supertest - .put(`/api/fleet/agent_policies/${agentPolicy.id}`) - .set('kbn-xsrf', 'xxxx') - .send({ - name: agentPolicy.name, - namespace: agentPolicy.namespace, - is_managed: false, - force: true, - }) - .expect(200); + it('should work for regular policies', async function () { + await supertest + .delete(`/api/fleet/package_policies/${packagePolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .expect(200); + }); + + it('should work if the package policy is already deleted', async function () { + await supertest + .delete(`/api/fleet/package_policies/${packagePolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .expect(200); + await supertest + .delete(`/api/fleet/package_policies/${packagePolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .expect(200); + }); }); + describe('Delete bulk', () => { + let agentPolicy: any; + let packagePolicy: any; + before(async () => { + await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await getService('esArchiver').load( + 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' + ); + }); + before(async function () { + let agentPolicyResponse = await supertest + .post(`/api/fleet/agent_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: false, + }); + + // if one already exists, re-use that + if (agentPolicyResponse.body.statusCode === 409) { + const errorRegex = /^agent policy \'(?[\w,\-]+)\' already exists/i; + const result = errorRegex.exec(agentPolicyResponse.body.message); + if (result?.groups?.id) { + agentPolicyResponse = await supertest + .put(`/api/fleet/agent_policies/${result.groups.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'Test policy', + namespace: 'default', + is_managed: false, + force: true, + }); + } + } + agentPolicy = agentPolicyResponse.body.item; + + const { body: packagePolicyResponse } = await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'filetest-1', + description: '', + namespace: 'default', + policy_id: agentPolicy.id, + enabled: true, + output_id: '', + inputs: [], + package: { + name: 'filetest', + title: 'For File Tests', + version: '0.1.0', + }, + }); + packagePolicy = packagePolicyResponse.item; + }); + + after(async function () { + await supertest + .post(`/api/fleet/agent_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ agentPolicyId: agentPolicy.id }); + + await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true, packagePolicyIds: [packagePolicy.id] }); + }); + after(async () => { + await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await getService('esArchiver').unload( + 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' + ); + }); + + it('should fail on hosted agent policies', async function () { + // update existing policy to hosted + await supertest + .put(`/api/fleet/agent_policies/${agentPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: agentPolicy.name, + namespace: agentPolicy.namespace, + is_managed: true, + }) + .expect(200); + + // try to delete + const { body: results } = await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ packagePolicyIds: [packagePolicy.id] }) + .expect(200); + + // delete always succeeds (returns 200) with Array<{success: boolean}> + expect(Array.isArray(results)); + expect(results.length).to.be(1); + expect(results[0].success).to.be(false); + expect(results[0].body.message).to.contain( + 'Cannot remove integrations of hosted agent policy' + ); + + // same, but with force + const { body: resultsWithForce } = await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true, packagePolicyIds: [packagePolicy.id] }) + .expect(200); + + // delete always succeeds (returns 200) with Array<{success: boolean}> + expect(Array.isArray(resultsWithForce)); + expect(resultsWithForce.length).to.be(1); + expect(resultsWithForce[0].success).to.be(true); + + // revert existing policy to regular + await supertest + .put(`/api/fleet/agent_policies/${agentPolicy.id}`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: agentPolicy.name, + namespace: agentPolicy.namespace, + is_managed: false, + force: true, + }) + .expect(200); + }); - it('should work for regular policies', async function () { - await supertest - .post(`/api/fleet/package_policies/delete`) - .set('kbn-xsrf', 'xxxx') - .send({ packagePolicyIds: [packagePolicy.id] }); + it('should work for regular policies', async function () { + await supertest + .post(`/api/fleet/package_policies/delete`) + .set('kbn-xsrf', 'xxxx') + .send({ packagePolicyIds: [packagePolicy.id] }) + .expect(200); + }); }); }); } From cee2689116a79d53019617a42fb49d4c7f963b01 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 11 Aug 2022 10:14:13 -0400 Subject: [PATCH 16/59] [Fleet] Fix tag creation (#138603) --- .../components/tags_add_remove.test.tsx | 21 +++++++++++++++++++ .../components/tags_add_remove.tsx | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.test.tsx index a4a06e1ff55120..69c6f3c12823e6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.test.tsx @@ -108,6 +108,27 @@ describe('TagsAddRemove', () => { ); }); + it('should show allow to add new tag when agent do not have any tags', () => { + allTags = []; + selectedTags = []; + const result = renderComponent('agent1'); + const searchInput = result.getByTestId('addRemoveTags'); + + fireEvent.input(searchInput, { + target: { value: 'tag' }, + }); + + fireEvent.click(result.getByTestId('createTagBtn')); + + expect(mockUpdateTags).toHaveBeenCalledWith( + 'agent1', + ['tag'], + expect.anything(), + 'Tag created', + 'Tag creation failed' + ); + }); + it('should add new tag when not found in search and button clicked', () => { const result = renderComponent('agent1'); const searchInput = result.getByRole('combobox'); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.tsx index 55272497a69606..ccbb50d3eec714 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/tags_add_remove.tsx @@ -212,7 +212,7 @@ export const TagsAddRemove: React.FC = ({ )} - {!isExactMatch && labels.length && searchValue !== '' ? createTagButton : null} + {(!isExactMatch || labels.length === 0) && searchValue !== '' ? createTagButton : null} ); From 7cb83df66e264c29d9df3e75f0e3bf69419ab266 Mon Sep 17 00:00:00 2001 From: Kevin Logan <56395104+kevinlog@users.noreply.github.com> Date: Thu, 11 Aug 2022 10:37:50 -0400 Subject: [PATCH 17/59] [Security Solution] Update text and Response Console product name (#138549) --- packages/kbn-doc-links/src/get_doc_links.ts | 1 + packages/kbn-doc-links/src/types.ts | 1 + .../responder_context_menu_item.tsx | 2 +- .../take_action_dropdown/index.test.tsx | 6 +++--- .../console/components/command_list.tsx | 20 ++++++++++--------- .../side_panel/side_panel_content_manager.tsx | 10 +--------- .../endpoint_responder/action_log_button.tsx | 2 +- .../translations.tsx | 2 +- .../use_with_show_endpoint_responder.tsx | 2 +- .../view/hooks/use_endpoint_action_items.tsx | 2 +- 10 files changed, 22 insertions(+), 26 deletions(-) diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 380c706696b9d9..fe2206033a2b85 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -359,6 +359,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { macos_system_ext: `${SECURITY_SOLUTION_DOCS}deploy-elastic-endpoint.html#system-extension-endpoint`, linux_deadlock: `${SECURITY_SOLUTION_DOCS}ts-management.html`, }, + responseActions: `${SECURITY_SOLUTION_DOCS}response-actions.html`, }, query: { eql: `${ELASTICSEARCH_DOCS}eql.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 4153f9579321a0..99396183fc64f6 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -264,6 +264,7 @@ export interface DocLinks { linux_deadlock: string; }; readonly threatIntelInt: string; + readonly responseActions: string; }; readonly query: { readonly eql: string; diff --git a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_context_menu_item.tsx b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_context_menu_item.tsx index 6fea341cbc0ee6..ccab3a650b605e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_context_menu_item.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/endpoint_responder/responder_context_menu_item.tsx @@ -100,7 +100,7 @@ export const ResponderContextMenuItem = memo( > ); diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx index 4481c8a5c93a45..01e676189f79ee 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx @@ -234,11 +234,11 @@ describe('take action dropdown', () => { ); }); }); - test('should render "Launch responder"', async () => { + test('should render "Respond"', async () => { await waitFor(() => { expect( wrapper.find('[data-test-subj="endpointResponseActions-action-item"]').first().text() - ).toEqual('Launch responder'); + ).toEqual('Respond'); }); }); }); @@ -366,7 +366,7 @@ describe('take action dropdown', () => { }); }); - describe('should correctly enable/disable the "Launch responder" button', () => { + describe('should correctly enable/disable the "Respond" button', () => { let wrapper: ReactWrapper; let apiMocks: ReturnType; diff --git a/x-pack/plugins/security_solution/public/management/components/console/components/command_list.tsx b/x-pack/plugins/security_solution/public/management/components/console/components/command_list.tsx index 810b8c61626447..cd26945b6a0277 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/components/command_list.tsx +++ b/x-pack/plugins/security_solution/public/management/components/console/components/command_list.tsx @@ -31,6 +31,7 @@ import { useConsoleStateDispatch } from '../hooks/state_selectors/use_console_st import { COMMON_ARGS, HELP_GROUPS } from '../service/builtin_commands'; import { getCommandNameWithArgs } from '../service/utils'; import { ConsoleCodeBlock } from './console_code_block'; +import { useKibana } from '../../../../common/lib/kibana'; // @ts-expect-error TS2769 const StyledEuiBasicTable = styled(EuiBasicTable)` @@ -74,6 +75,7 @@ export interface CommandListProps { export const CommandList = memo(({ commands, display = 'default' }) => { const getTestId = useTestIdGenerator(useDataTestSubj()); const dispatch = useConsoleStateDispatch(); + const { docLinks } = useKibana().services; const footerMessage = useMemo(() => { return ( @@ -228,21 +230,21 @@ export const CommandList = memo(({ commands, display = 'defaul const calloutItems = [ , , + learnMore: ( + ), @@ -255,17 +257,17 @@ export const CommandList = memo(({ commands, display = 'defaul title={ } > -

    +
      {calloutItems.map((item, index) => (
    • {item}
    • ))} -
+ ); diff --git a/x-pack/plugins/security_solution/public/management/components/console/components/side_panel/side_panel_content_manager.tsx b/x-pack/plugins/security_solution/public/management/components/console/components/side_panel/side_panel_content_manager.tsx index 6c3c6207b548ca..a3ccf282898b70 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/components/side_panel/side_panel_content_manager.tsx +++ b/x-pack/plugins/security_solution/public/management/components/console/components/side_panel/side_panel_content_manager.tsx @@ -70,17 +70,9 @@ export const SidePanelContentManager = memo(() => { , - addText: ( - - - - ), }} /> diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx index d906a09cc53784..bdfd987af131b9 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx @@ -30,7 +30,7 @@ export const ActionLogButton = memo((p > {showActionLogFlyout && ( diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx index 0fadb24a0fd0c4..04255a9ceaf533 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx @@ -92,7 +92,7 @@ export const TABLE_COLUMN_NAMES = Object.freeze({ export const UX_MESSAGES = Object.freeze({ flyoutTitle: (hostname: string) => i18n.translate('xpack.securitySolution.responseActionsList.flyout.title', { - defaultMessage: `Action log : {hostname}`, + defaultMessage: `Actions log : {hostname}`, values: { hostname }, }), pageTitle: i18n.translate('xpack.securitySolution.responseActionsList.list.title', { diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx index 4c16dcbaed2c97..1d8808ca52d76d 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_with_show_endpoint_responder.tsx @@ -20,7 +20,7 @@ import { OfflineCallout } from '../../components/endpoint_responder/offline_call type ShowEndpointResponseActionsConsole = (endpointMetadata: HostMetadata) => void; const RESPONDER_PAGE_TITLE = i18n.translate('xpack.securitySolution.responder_overlay.pageTitle', { - defaultMessage: 'Responder', + defaultMessage: 'Response console', }); export const useWithShowEndpointResponder = (): ShowEndpointResponseActionsConsole => { diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx index cad9f0d61ee7ef..b3e1ce76480f3a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/hooks/use_endpoint_action_items.tsx @@ -136,7 +136,7 @@ export const useEndpointActionItems = ( children: ( ), toolTipContent: !isResponderCapabilitiesEnabled From 69e54be4b65b6ffe5149e488ba8b4900384a524d Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Thu, 11 Aug 2022 16:51:24 +0200 Subject: [PATCH 18/59] Switch to the new `Get User Profile` request and response signatures. Fix Bulk Get User Profiles API to properly serialize parameters on the browser side. (#138361) --- .buildkite/ftr_configs.yml | 1 + .../containers/user_profiles/api.mock.ts | 3 + .../security/common/model/user_profile.ts | 5 + .../user_profile_api_client.test.ts | 7 + .../user_profile/user_profile_api_client.ts | 3 +- .../user_profile/user_profile_service.test.ts | 163 ++++++++---------- .../user_profile/user_profile_service.ts | 68 +++----- .../functional/apps/security/user_email.ts | 10 +- .../tests/user_profiles/bulk_get.ts | 3 +- .../tests/user_profiles/get_current.ts | 3 +- .../common/test_endpoints/kibana.json | 1 + .../common/test_endpoints/public/plugin.tsx | 42 ++++- .../tests/user_profiles/client_side_apis.ts | 101 +++++++++++ .../tests/user_profiles/index.ts | 14 ++ .../user_profiles.config.ts | 47 +++++ 15 files changed, 322 insertions(+), 149 deletions(-) create mode 100644 x-pack/test/security_functional/tests/user_profiles/client_side_apis.ts create mode 100644 x-pack/test/security_functional/tests/user_profiles/index.ts create mode 100644 x-pack/test/security_functional/user_profiles.config.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index 3395b422e793d9..c10bf18e5e9177 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -250,6 +250,7 @@ enabled: - x-pack/test/security_functional/oidc.config.ts - x-pack/test/security_functional/saml.config.ts - x-pack/test/security_functional/insecure_cluster_warning.config.ts + - x-pack/test/security_functional/user_profiles.config.ts - x-pack/test/security_solution_endpoint_api_int/config.ts - x-pack/test/security_solution_endpoint/config.ts - x-pack/test/session_view/basic/config.ts diff --git a/x-pack/plugins/cases/public/containers/user_profiles/api.mock.ts b/x-pack/plugins/cases/public/containers/user_profiles/api.mock.ts index 57578086ceddfd..e9382f7092ae01 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/api.mock.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/api.mock.ts @@ -10,6 +10,7 @@ import { UserProfile } from '@kbn/security-plugin/common'; export const userProfiles: UserProfile[] = [ { uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0', + enabled: true, data: {}, user: { username: 'damaged_raccoon', @@ -19,6 +20,7 @@ export const userProfiles: UserProfile[] = [ }, { uid: 'u_A_tM4n0wPkdiQ9smmd8o0Hr_h61XQfu8aRPh9GMoRoc_0', + enabled: true, data: {}, user: { username: 'physical_dinosaur', @@ -28,6 +30,7 @@ export const userProfiles: UserProfile[] = [ }, { uid: 'u_9xDEQqUqoYCnFnPPLq5mIRHKL8gBTo_NiKgOnd5gGk0_0', + enabled: true, data: {}, user: { username: 'wet_dingo', diff --git a/x-pack/plugins/security/common/model/user_profile.ts b/x-pack/plugins/security/common/model/user_profile.ts index c6156982aab7e7..68ec11bf1ede44 100644 --- a/x-pack/plugins/security/common/model/user_profile.ts +++ b/x-pack/plugins/security/common/model/user_profile.ts @@ -28,6 +28,11 @@ export interface UserProfile { */ uid: string; + /** + * Indicates whether user profile is enabled or not. + */ + enabled: boolean; + /** * Information about the user that owns profile. */ diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.test.ts b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.test.ts index ca42685709844d..4fdb482a2cbae6 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.test.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.test.ts @@ -39,4 +39,11 @@ describe('UserProfileAPIClient', () => { body: '{"avatar":{"imageUrl":"avatar.png"}}', }); }); + + it('should get user profiles in bulk', async () => { + await apiClient.bulkGet({ uids: new Set(['UID-1', 'UID-2']), dataPath: '*' }); + expect(coreStart.http.post).toHaveBeenCalledWith('/internal/security/user_profile/_bulk_get', { + body: '{"uids":["UID-1","UID-2"],"dataPath":"*"}', + }); + }); }); diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts index 6c4c53ef4ec307..a2fc60f7b4d758 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile_api_client.ts @@ -94,7 +94,8 @@ export class UserProfileAPIClient { */ public bulkGet(params: UserProfileBulkGetParams) { return this.http.post>>('/internal/security/user_profile/_bulk_get', { - body: JSON.stringify(params), + // Convert `Set` with UIDs to an array to make it serializable. + body: JSON.stringify({ ...params, uids: [...params.uids] }), }); } diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts index c11b1fe85da573..9254a46c0e8c53 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts @@ -81,7 +81,7 @@ describe('UserProfileService', () => { }); mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ - [mockUserProfile.uid]: mockUserProfile, + profiles: [mockUserProfile], } as unknown as SecurityGetUserProfileResponse); }); @@ -160,6 +160,33 @@ describe('UserProfileService', () => { }); }); + it('fails if cannot find user profile', async () => { + mockStartParams.session.get.mockResolvedValue( + sessionMock.createValue({ userProfileId: mockUserProfile.uid }) + ); + + mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ + profiles: [], + } as unknown as SecurityGetUserProfileResponse); + + const startContract = userProfileService.start(mockStartParams); + await expect( + startContract.getCurrent({ request: mockRequest }) + ).rejects.toMatchInlineSnapshot(`[Error: User profile is not found.]`); + + expect(mockStartParams.session.get).toHaveBeenCalledTimes(1); + expect(mockStartParams.session.get).toHaveBeenCalledWith(mockRequest); + + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledTimes(1); + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledWith({ + uid: 'UID', + }); + }); + it('properly parses returned profile', async () => { mockStartParams.session.get.mockResolvedValue( sessionMock.createValue({ userProfileId: mockUserProfile.uid }) @@ -206,10 +233,12 @@ describe('UserProfileService', () => { ); mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ - [mockUserProfile.uid]: userProfileMock.createWithSecurity({ - ...mockUserProfile, - data: { kibana: { avatar: 'fun.gif' }, other_app: { secret: 'data' } }, - }), + profiles: [ + userProfileMock.createWithSecurity({ + ...mockUserProfile, + data: { kibana: { avatar: 'fun.gif' }, other_app: { secret: 'data' } }, + }), + ], } as unknown as SecurityGetUserProfileResponse); const startContract = userProfileService.start(mockStartParams); @@ -460,32 +489,32 @@ describe('UserProfileService', () => { describe('#bulkGet', () => { it('properly parses and sorts returned profiles', async () => { - mockStartParams.clusterClient.asInternalUser.transport.request.mockResolvedValue({ + mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ profiles: [ userProfileMock.createWithSecurity({ - uid: 'UID-2', + uid: 'UID-1', user: { - username: 'user-2', - display_name: 'display-name-2', - full_name: 'full-name-2', + username: 'user-1', + display_name: 'display-name-1', + full_name: 'full-name-1', realm_name: 'some-realm', realm_domain: 'some-domain', - roles: ['role-2'], + roles: ['role-1'], }, }), userProfileMock.createWithSecurity({ - uid: 'UID-1', + uid: 'UID-2', user: { - username: 'user-1', - display_name: 'display-name-1', - full_name: 'full-name-1', + username: 'user-2', + display_name: 'display-name-2', + full_name: 'full-name-2', realm_name: 'some-realm', realm_domain: 'some-domain', - roles: ['role-1'], + roles: ['role-2'], }, }), ], - }); + } as unknown as SecurityGetUserProfileResponse); const startContract = userProfileService.start(mockStartParams); await expect(startContract.bulkGet({ uids: new Set(['UID-1', 'UID-2']) })).resolves @@ -515,72 +544,25 @@ describe('UserProfileService', () => { }, ] `); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledTimes( - 1 - ); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledWith({ - method: 'POST', - path: '_security/profile/_suggest', - body: { hint: { uids: ['UID-1', 'UID-2'] }, size: 2 }, - }); - }); - - it('filters out not requested profiles', async () => { - mockStartParams.clusterClient.asInternalUser.transport.request.mockResolvedValue({ - profiles: [ - userProfileMock.createWithSecurity({ uid: 'UID-2' }), - userProfileMock.createWithSecurity({ uid: 'UID-NOT-REQUESTED' }), - userProfileMock.createWithSecurity({ uid: 'UID-1' }), - ], - }); - - const startContract = userProfileService.start(mockStartParams); - await expect(startContract.bulkGet({ uids: new Set(['UID-1', 'UID-2', 'UID-3']) })).resolves - .toMatchInlineSnapshot(` - Array [ - Object { - "data": Object {}, - "enabled": true, - "uid": "UID-1", - "user": Object { - "display_name": undefined, - "email": "some@email", - "full_name": undefined, - "username": "some-username", - }, - }, - Object { - "data": Object {}, - "enabled": true, - "uid": "UID-2", - "user": Object { - "display_name": undefined, - "email": "some@email", - "full_name": undefined, - "username": "some-username", - }, - }, - ] - `); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledTimes( - 1 - ); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledWith({ - method: 'POST', - path: '_security/profile/_suggest', - body: { hint: { uids: ['UID-1', 'UID-2', 'UID-3'] }, size: 3 }, + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledTimes(1); + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledWith({ + uid: 'UID-1,UID-2', }); }); it('should request data if data path is specified', async () => { - mockStartParams.clusterClient.asInternalUser.transport.request.mockResolvedValue({ + mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockResolvedValue({ profiles: [ userProfileMock.createWithSecurity({ uid: 'UID-1', data: { some: 'data', kibana: { some: 'kibana-data' } }, }), ], - }); + } as unknown as SecurityGetUserProfileResponse); const startContract = userProfileService.start(mockStartParams); await expect(startContract.bulkGet({ uids: new Set(['UID-1']), dataPath: '*' })).resolves @@ -601,17 +583,14 @@ describe('UserProfileService', () => { }, ] `); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledTimes( - 1 - ); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledWith({ - method: 'POST', - path: '_security/profile/_suggest', - body: { - hint: { uids: ['UID-1'] }, - data: 'kibana.*', - size: 1, - }, + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledTimes(1); + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledWith({ + uid: 'UID-1', + data: 'kibana.*', }); }); @@ -619,7 +598,7 @@ describe('UserProfileService', () => { const failureReason = new errors.ResponseError( securityMock.createApiResponse({ statusCode: 500, body: 'some message' }) ); - mockStartParams.clusterClient.asInternalUser.transport.request.mockRejectedValue( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile.mockRejectedValue( failureReason ); @@ -627,13 +606,13 @@ describe('UserProfileService', () => { await expect(startContract.bulkGet({ uids: new Set(['UID-1', 'UID-2']) })).rejects.toBe( failureReason ); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledTimes( - 1 - ); - expect(mockStartParams.clusterClient.asInternalUser.transport.request).toHaveBeenCalledWith({ - method: 'POST', - path: '_security/profile/_suggest', - body: { hint: { uids: ['UID-1', 'UID-2'] }, size: 2 }, + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledTimes(1); + expect( + mockStartParams.clusterClient.asInternalUser.security.getUserProfile + ).toHaveBeenCalledWith({ + uid: 'UID-1,UID-2', }); }); }); diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.ts index 32dc1ec51cd882..7be2abe07a24a0 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.ts @@ -7,7 +7,7 @@ import type { SecurityActivateUserProfileRequest, - SecuritySuggestUserProfilesResponse, + SecurityUserProfileWithMetadata, } from '@elastic/elasticsearch/lib/api/types'; import type { SecurityUserProfile } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -179,8 +179,10 @@ function parseUserProfile( ): UserProfile { return { uid: rawUserProfile.uid, - // @ts-expect-error @elastic/elasticsearch SecurityActivateUserProfileResponse.enabled: boolean - enabled: rawUserProfile.enabled, + // Get User Profile API returns `enabled` property, but Suggest User Profile API doesn't since it's assumed that the + // API returns only enabled profiles. To simplify the API in Kibana we use the same interfaces for user profiles + // irrespective to the source they are coming from, so we need to "normalize" `enabled` property here. + enabled: rawUserProfile.enabled ?? true, data: rawUserProfile.data?.[KIBANA_DATA_ROOT] ?? {}, user: { username: rawUserProfile.user.username, @@ -315,12 +317,13 @@ export class UserProfileService { return null; } + let body; try { - const body = await clusterClient.asInternalUser.security.getUserProfile({ + // @ts-expect-error Invalid response format. + body = (await clusterClient.asInternalUser.security.getUserProfile({ uid: userSession.userProfileId, data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, - }); - return parseUserProfileWithSecurity(body[userSession.userProfileId]!); + })) as { profiles: SecurityUserProfileWithMetadata[] }; } catch (error) { this.logger.error( `Failed to retrieve user profile for the current user [sid=${getPrintableSessionId( @@ -329,6 +332,17 @@ export class UserProfileService { ); throw error; } + + if (body.profiles.length === 0) { + this.logger.error( + `The user profile for the current user [sid=${getPrintableSessionId( + userSession.sid + )}] is not found.` + ); + throw new Error(`User profile is not found.`); + } + + return parseUserProfileWithSecurity(body.profiles[0]); } /** @@ -343,41 +357,13 @@ export class UserProfileService { } try { - // Use `transport.request` since `.security.suggestUserProfiles` implementation doesn't accept `hint` as a body - // parameter yet. - const body = - await clusterClient.asInternalUser.transport.request({ - method: 'POST', - path: '_security/profile/_suggest', - body: { - hint: { uids: [...uids] }, - // We need at most as many results as requested uids. - size: uids.size, - data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, - }, - }); - - // Using `_suggest` API to simulate `_bulk_get` API has two important shortcomings: - // 1. "uids" parameter is just a hint that asks Elasticsearch to put user profiles with the requested uids on the - // top of the returned list, but if Elasticsearch cannot find user profiles for all requested uids it might - // include other "matched" user profiles as well. We should filter those non-requested profiles out. - // 2. The `_suggest` API is supposed to sort results by relevance i.e. first by the search score (if `name` - // parameter is specified which isn't the case here) and then by the activation time. The `_bulk_get` API, on the - // contrary, should always return results in the order the consumer specified UIDs in (in our case, the insertion - // order for the `Set` we use as the UIDs parameter). That's why we're manually sorting profiles here. - const rawUserProfiles = new Map( - body.profiles.map((rawUserProfile) => [rawUserProfile.uid, rawUserProfile]) - ); - - const parsedUserProfiles = []; - for (const uid of uids) { - const rawUserProfile = rawUserProfiles.get(uid); - if (rawUserProfile) { - parsedUserProfiles.push(parseUserProfile(rawUserProfile)); - } - } + // @ts-expect-error Invalid response format. + const body = (await clusterClient.asInternalUser.security.getUserProfile({ + uid: [...uids].join(','), + data: dataPath ? `${KIBANA_DATA_ROOT}.${dataPath}` : undefined, + })) as { profiles: SecurityUserProfileWithMetadata[] }; - return parsedUserProfiles; + return body.profiles.map((rawUserProfile) => parseUserProfile(rawUserProfile)); } catch (error) { this.logger.error(`Failed to bulk get user profiles: ${getDetailedErrorMessage(error)}`); throw error; @@ -493,7 +479,7 @@ export class UserProfileService { // but still iterate through entire batch to collect and report all unknown uids. if (filteredProfile && filteredProfiles.length < requiredSize) { filteredProfiles.push(filteredProfile); - } else { + } else if (!filteredProfile) { unknownUids.push(profileUid); } } diff --git a/x-pack/test/functional/apps/security/user_email.ts b/x-pack/test/functional/apps/security/user_email.ts index 3d50e4cbbd22a3..fd33d6fca4d8ad 100644 --- a/x-pack/test/functional/apps/security/user_email.ts +++ b/x-pack/test/functional/apps/security/user_email.ts @@ -13,14 +13,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['security', 'settings', 'common', 'accountSetting']); const log = getService('log'); const security = getService('security'); - const kibanaServer = getService('kibanaServer'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/138528 - describe.skip('useremail', function () { + describe('useremail', function () { before(async () => { - await kibanaServer.importExport.load( - 'x-pack/test/functional/fixtures/kbn_archiver/security/discover' - ); await security.testUser.setRoles(['cluster_security_manager']); await PageObjects.settings.navigateTo(); await PageObjects.security.clickElasticsearchUsers(); @@ -63,9 +58,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async function () { // NOTE: Logout needs to happen before anything else to avoid flaky behavior await PageObjects.security.forceLogout(); - await kibanaServer.importExport.unload( - 'x-pack/test/functional/fixtures/kbn_archiver/security/discover' - ); await security.testUser.restoreDefaults(); }); }); diff --git a/x-pack/test/security_api_integration/tests/user_profiles/bulk_get.ts b/x-pack/test/security_api_integration/tests/user_profiles/bulk_get.ts index 985d2ac8f0d099..8955a06261848f 100644 --- a/x-pack/test/security_api_integration/tests/user_profiles/bulk_get.ts +++ b/x-pack/test/security_api_integration/tests/user_profiles/bulk_get.ts @@ -14,8 +14,7 @@ export default function ({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); const security = getService('security'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/138528 - describe.skip('Getting user profiles in bulk', () => { + describe('Getting user profiles in bulk', () => { const usersSessions = new Map(); before(async () => { // 1. Create test users diff --git a/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts b/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts index 786059642c9d2c..d7f23545aecd00 100644 --- a/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts +++ b/x-pack/test/security_api_integration/tests/user_profiles/get_current.ts @@ -12,8 +12,7 @@ export default function ({ getService }: FtrProviderContext) { const supertestWithoutAuth = getService('supertestWithoutAuth'); const security = getService('security'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/138528 - describe.skip('Getting user profile for the current user', () => { + describe('Getting user profile for the current user', () => { const testUserName = 'user_with_profile'; async function login() { diff --git a/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json b/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json index 71af8e99d3940a..6546325cb2d68f 100644 --- a/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json +++ b/x-pack/test/security_functional/fixtures/common/test_endpoints/kibana.json @@ -3,6 +3,7 @@ "owner": { "name": "Platform Security", "githubTeam": "kibana-security" }, "version": "8.0.0", "kibanaVersion": "kibana", + "requiredPlugins":["security"], "server": true, "ui": true } diff --git a/x-pack/test/security_functional/fixtures/common/test_endpoints/public/plugin.tsx b/x-pack/test/security_functional/fixtures/common/test_endpoints/public/plugin.tsx index 3cb36e7c1fe78f..85918b250dc624 100644 --- a/x-pack/test/security_functional/fixtures/common/test_endpoints/public/plugin.tsx +++ b/x-pack/test/security_functional/fixtures/common/test_endpoints/public/plugin.tsx @@ -10,9 +10,14 @@ import ReactDOM from 'react-dom'; import React from 'react'; import { debounce, filter, first } from 'rxjs/operators'; import { timer } from 'rxjs'; +import { SecurityPluginStart } from '@kbn/security-plugin/public'; -export class TestEndpointsPlugin implements Plugin { - public setup(core: CoreSetup) { +export interface PluginStartDependencies { + security: SecurityPluginStart; +} + +export class TestEndpointsPlugin implements Plugin { + public setup(core: CoreSetup) { // Prevent auto-logout on server `401` errors. core.http.anonymousPaths.register('/authentication/app'); @@ -39,6 +44,39 @@ export class TestEndpointsPlugin implements Plugin { return () => ReactDOM.unmountComponentAtNode(element); }, }); + + core.application.register({ + id: 'user_profiles_app', + title: 'User Profiles app', + async mount({ element }) { + const [, { security }] = await core.getStartServices(); + + const [currentUserProfile, otherUserProfiles] = await Promise.all([ + security.userProfiles.getCurrent({ dataPath: '*' }), + security.userProfiles.bulkGet({ + uids: new Set(new URLSearchParams(location.search).getAll('uid')), + dataPath: '*', + }), + ]); + + ReactDOM.render( +
+
+ {currentUserProfile?.user.username}:{JSON.stringify(currentUserProfile?.data)} +
+ {otherUserProfiles.map((userProfile) => ( +
+ {userProfile.user.username}:{JSON.stringify(userProfile.data)} +
+ ))} +
, + element + ); + return () => ReactDOM.unmountComponentAtNode(element); + }, + }); } public start() {} public stop() {} diff --git a/x-pack/test/security_functional/tests/user_profiles/client_side_apis.ts b/x-pack/test/security_functional/tests/user_profiles/client_side_apis.ts new file mode 100644 index 00000000000000..0e1fb7879d81a2 --- /dev/null +++ b/x-pack/test/security_functional/tests/user_profiles/client_side_apis.ts @@ -0,0 +1,101 @@ +/* + * 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 expect from '@kbn/expect'; +import { parse as parseCookie } from 'tough-cookie'; +import { adminTestUser } from '@kbn/test'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['security', 'common']); + const testSubjects = getService('testSubjects'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const security = getService('security'); + const retry = getService('retry'); + + describe('User Profiles client side APIs', function () { + const userProfileUids: string[] = []; + before(async () => { + // 1. Create test users + await Promise.all( + ['one', 'two', 'three'].map((userPrefix) => + security.user.create(`user_${userPrefix}`, { + password: 'changeme', + roles: [`role_${userPrefix}`], + }) + ) + ); + + // 2. Activate user profiles and update data. + for (const userPrefix of ['one', 'two', 'three']) { + const response = await supertestWithoutAuth + .post('/internal/security/login') + .set('kbn-xsrf', 'xxx') + .send({ + providerType: 'basic', + providerName: 'basic', + currentURL: '/', + params: { username: `user_${userPrefix}`, password: 'changeme' }, + }) + .expect(200); + + const cookie = parseCookie(response.headers['set-cookie'][0])!.cookieString(); + await supertestWithoutAuth + .post('/internal/security/user_profile/_data') + .set('kbn-xsrf', 'xxx') + .set('Cookie', cookie) + .send({ some: `data-${userPrefix}` }) + .expect(200); + + const { body: profile } = await supertestWithoutAuth + .get('/internal/security/user_profile') + .set('Cookie', cookie) + .expect(200); + + userProfileUids.push(profile.uid); + } + }); + + after(async () => { + await Promise.all( + ['one', 'two', 'three'].map((userPrefix) => security.user.delete(`user_${userPrefix}`)) + ); + }); + + beforeEach(async () => { + await PageObjects.security.loginPage.login(undefined, undefined, { expectSuccess: true }); + }); + + afterEach(async () => { + // NOTE: Logout needs to happen before anything else to avoid flaky behavior + await PageObjects.security.forceLogout(); + }); + + it('can retrieve own user profile and user profiles for other users', async () => { + await PageObjects.common.navigateToUrlWithBrowserHistory( + 'user_profiles_app', + '', + `?${userProfileUids.map((uid) => `uid=${uid}`).join('&')}`, + { ensureCurrentUrl: true, shouldLoginIfPrompted: false } + ); + + await retry.try(async () => { + const currentUserProfileText = await testSubjects.getVisibleText( + 'testEndpointsUserProfilesAppCurrentUserProfile' + ); + expect(currentUserProfileText).to.equal(`${adminTestUser.username}:{}`); + + for (const userPrefix of ['one', 'two', 'three']) { + const userProfileText = await testSubjects.getVisibleText( + `testEndpointsUserProfilesAppUserProfile_user_${userPrefix}` + ); + expect(userProfileText).to.equal(`user_${userPrefix}:{"some":"data-${userPrefix}"}`); + } + }); + }); + }); +} diff --git a/x-pack/test/security_functional/tests/user_profiles/index.ts b/x-pack/test/security_functional/tests/user_profiles/index.ts new file mode 100644 index 00000000000000..85c74150dd3bdf --- /dev/null +++ b/x-pack/test/security_functional/tests/user_profiles/index.ts @@ -0,0 +1,14 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('security app - user profiles', function () { + loadTestFile(require.resolve('./client_side_apis')); + }); +} diff --git a/x-pack/test/security_functional/user_profiles.config.ts b/x-pack/test/security_functional/user_profiles.config.ts new file mode 100644 index 00000000000000..f9bed9ce380dfa --- /dev/null +++ b/x-pack/test/security_functional/user_profiles.config.ts @@ -0,0 +1,47 @@ +/* + * 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 { resolve } from 'path'; +import { FtrConfigProviderContext } from '@kbn/test'; +import { services } from '../functional/services'; +import { pageObjects } from '../functional/page_objects'; + +// the default export of config files must be a config provider +// that returns an object with the projects config values +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const xPackKibanaFunctionalConfig = await readConfigFile( + require.resolve('../functional/config.base.js') + ); + + const testEndpointsPlugin = resolve(__dirname, './fixtures/common/test_endpoints'); + + return { + testFiles: [resolve(__dirname, './tests/user_profiles')], + + services, + pageObjects, + + servers: xPackKibanaFunctionalConfig.get('servers'), + esTestCluster: xPackKibanaFunctionalConfig.get('esTestCluster'), + + kbnTestServer: { + ...xPackKibanaFunctionalConfig.get('kbnTestServer'), + serverArgs: [ + ...xPackKibanaFunctionalConfig.get('kbnTestServer.serverArgs'), + `--plugin-path=${testEndpointsPlugin}`, + ], + }, + apps: { + ...xPackKibanaFunctionalConfig.get('apps'), + user_profiles_app: { pathname: '/app/user_profiles_app' }, + }, + + junit: { + reportName: 'Chrome X-Pack Security Functional Tests (User Profiles)', + }, + }; +} From 088c1b63118e6aedd112a791e39bf973e0b251d5 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 11 Aug 2022 11:05:09 -0400 Subject: [PATCH 19/59] [Security Solution][Endpoint] Fix/un-skip jest tests for Host Isolation Exceptions (#138566) Maybe it will work Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../view/components/form.test.tsx | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx index 9287931ddb11ee..43245b340e47c7 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/form.test.tsx @@ -92,9 +92,7 @@ describe('When on the host isolation exceptions entry form', () => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/136165 - // FLAKY: https://github.com/elastic/kibana/issues/136166 - describe.skip('and creating a new exception', () => { + describe('and creating a new exception', () => { beforeEach(async () => { await render(); }); @@ -107,32 +105,35 @@ describe('When on the host isolation exceptions entry form', () => { ).toHaveValue(''); }); - it.each(['not an ip', '100', '900.0.0.1', 'x.x.x.x', '10.0.0'])( + it('should keep submit button disabled if only the name is entered', async () => { + const nameInput = renderResult.getByTestId('hostIsolationExceptions-form-name-input'); + + userEvent.type(nameInput, 'test name'); + userEvent.click(renderResult.getByTestId('hostIsolationExceptions-form-description-input')); + + await waitFor(() => { + expect(submitButtonDisabledState()).toBe(true); + }); + }); + + it.each([['not an ip'], ['100'], ['900.0.0.1'], ['x.x.x.x'], ['10.0.0']])( 'should show validation error when a wrong ip value is entered. Case: "%s"', async (value: string) => { - const nameInput = renderResult.getByTestId('hostIsolationExceptions-form-name-input'); const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); - userEvent.type(nameInput, 'test name'); + userEvent.type(ipInput, value); + userEvent.click(renderResult.getByTestId('hostIsolationExceptions-form-description-input')); await waitFor(() => { + expect(formRowHasError('hostIsolationExceptions-form-ip-input-formRow')).toBe(true); expect(submitButtonDisabledState()).toBe(true); }); - - userEvent.type(ipInput, value); - userEvent.tab(); - - await waitFor(() => - expect(formRowHasError('hostIsolationExceptions-form-ip-input-formRow')).toBe(true) - ); - - await waitFor(() => expect(submitButtonDisabledState()).toBe(true)); } ); - it.each(['192.168.0.1', '10.0.0.1', '100.90.1.1/24', '192.168.200.6/30'])( + it.each([['192.168.0.1'], ['10.0.0.1'], ['100.90.1.1/24'], ['192.168.200.6/30']])( 'should NOT show validation error when a correct ip value is entered. Case: "%s"', - (value: string) => { + async (value: string) => { const ipInput = renderResult.getByTestId('hostIsolationExceptions-form-ip-input'); const nameInput = renderResult.getByTestId('hostIsolationExceptions-form-name-input'); @@ -140,7 +141,10 @@ describe('When on the host isolation exceptions entry form', () => { userEvent.type(ipInput, value); expect(formRowHasError('hostIsolationExceptions-form-ip-input-formRow')).toBe(false); - expect(submitButtonDisabledState()).toBe(false); + + await waitFor(() => { + expect(submitButtonDisabledState()).toBe(false); + }); } ); From 6ae880896945824fc2f97dbaeff9aabe687d6507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 11 Aug 2022 17:16:12 +0200 Subject: [PATCH 20/59] [DOCS] Updates screenshot for data viz in ML section. (#138524) --- .../ml/images/ml-data-visualizer-sample.jpg | Bin 547946 -> 0 bytes .../ml/images/ml-data-visualizer-sample.png | Bin 0 -> 683309 bytes docs/user/ml/index.asciidoc | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 docs/user/ml/images/ml-data-visualizer-sample.jpg create mode 100644 docs/user/ml/images/ml-data-visualizer-sample.png diff --git a/docs/user/ml/images/ml-data-visualizer-sample.jpg b/docs/user/ml/images/ml-data-visualizer-sample.jpg deleted file mode 100644 index 4d77ef3010c3f8b917bbb37daacb401c77d13f79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 547946 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 z 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

Kcpi zuq400s1Xgx-&^GBHvI6c1pw47Ns6UeV#_XcX2M1)4lYrd4S#??ifD1}Hu38VG3MB} z3VtwNm7l9Z`aWAqsEtMzWj$;e`mB>xvBxEzri)$I#m=rC({;FKUiGy#Jp-hOK{3{?AEl zwI2bYc&!hruGB%|wSahuTMuyu4)bXdOeRtO2t?W-r_2faBXpj0kSn?=5ruzBLkz@t zQfy=qI=#&-=0(WLfM_bK<$ zo~zY56Zr}19;F7me6LEcx0z4-;B1$?yfTWON&Hfvv*q@OfLK0M8}O30zc1z+2<^mF zL`z(an9zN721x!iH_U8KU_&3`uE|XN-)8%O={leY#`;ZGx7%24f&0DAfN6SwT9%ia z@?EaaTiLYVlMij<+V}g!9>-)H*l4qz#t6?-r&hE6JnfA zSKiUg?l7Oz6aA9g$MUKdjyV42{n(IMs+UKU?R89%;+k)(k^;)^^$Hf2ede?2-B$Qx z6kCt@p4d-MdTyI9cJJ(tIqifs&fdPuBj#m5bhhkvbRe<#r{1;1Ll#HQYd%MK-Yfi& zFaE^(zXI5?@N|%GDGS1YsdkpmbCm=Erj9^F_Ys|!7+%5#!ngen%DxX2g+o_@5}q^y z=ByLyorMr^26s%fp#_wuA+}&C1?@?<7{mE)I(Hsk1kYvQ>6Z%DTa3N4^eFn zRq|+w$zRN=sjRSXtpqxvV|$!{xh$A*E@4 zIRRf=11J_P#|SD+4xYgJI`Ro4jhDdFp`l;{$B*<*Co~Bt;8IbO*Dn z{`uI<8B?)tNdaSS_?$m*MrHz>yUcjMYI`AR&hTr!Ajzv|v$70q)0DXyxd>xT0^JJs zHdlCQS;-EKOjU9guENj><)b!n^a12h&IW>#L^7z%AmfXqdf?an&ohoaz=`vfH6NvUxWtNT3LuP0k&8f^SkR`U}t zM6I`nUll70V`~(}R~yn@h}Xt{eB1P_ZufhV&ehs-w^EG*k-2wC`b^U$t|n{U&*5=# z?xVYn=|G`z?rMkG$Vgy-y%xAnZYpRD6pwRUI<6=t%swaVhu+bJyS)d+;pl&o#P%{I zkLFVD<4;EVc9F_7dClaXYcrp0m`y+yLOSc*jcrY|#DhE)MO+`~g!!Wr+$w-U*& z`KP@oI)1UoH4eELc`m>;$hVm32xJ-e&udYhSMTDN^FI=M(Ie|2DY3FW_;-5t?-{di z!I)5&9~H0hwm~3O)yPQJ66m$pxxGfDzs6yxlD&_R_efZX;FW}vi{TS~n2y}MhfPrZ zDc~JZocWn-^k}PzyFcmiOW9l5>Hy(nYyU6@?%R@O_&Rs8)#zKhIqdx)kR(GZCs_@c3jzh@f=A(oG+X6YMvn~6YyeK84=#@Hh~E>;o+2G5s%>WWc?T}?F( z#g&}>^6~Lcu5Nqtp%f?LiTERjqZ=A=4T*P3O9`($bEPKSna%U-T+A0`lYOcpYh8%! zg^S@M50wTI)0(6@AiIYkb{=_9BxR77Flv};qz>?d*yVRqG)-kWb#-<1 zgw4X+BA3I)eU)WRdtD+5j=AWM^L}MX`~auVFO?H4oR!2J zjC@q5iCtVYZ`U7H@d^jmto@1ueLhz z+UdYTfa{s%9~S8p3&z$W)n4!XnZof3nUFC6AMCFJU;1Ij>Ix5!gNQJ%XqWz0G@Snc!P3ZdmJvA6TK-{;S2{{?~MD(`UL8GHM+4)y`?{ za>F=jwC&ox8>V?pzP^nJKg6X>f7XktK4N3~$LDyXUQV#Cs8Yy<2YaQrmAy1gT(c0j&bO7p*n}G8@ne z%I3p*Ylw};7*Oz~jt~Ue=pJK_uh7pR@cZ6pjF)$wT&yt{#}F_Oyu|IBE_)$+gGfoL z+YfIiwyn_ccv#fmTg>c69uOiJz^N2r?5uEWFQEy&qL3vhXW)7Z?->!xNqS}wN11IP zP9JYv?4~j)~?0(=bD~;BO{sZd}gTj9<7=YbCyRSO5hsK&2BBjh<_r(E`W^ zwb`cj=xvS}S7Eha0$kukW%99}`ZU9+0IQ(`oP)P=Tjb#`BPdvooav)Ipj68 zDqw9GHrqd&4ML~0Wkf1tB_5PqoKRGifw%n%mjv7)+=OPpwbqF#JT+sSv+5s`tys?q zAZOWC(w`djNoOTQv*rDYaoYv4sQb+CUsX_8q#wpQ?gbcZ#$n}@dsG}s{9%aQYX}WC z-#{g{wil0wmRzuU7bLt(59{E?$;_BcyU-p;lcjJ?_6yD*{8VGW;139`u*YmF7yLVH zg&{ehmQe(nNsQfiFIpe@0oy2We$ob$=x{o}546)nYc0({#KEiO{M7tfAyxO@wKuKf z`t|8B+LYd4<|#pOWo7j{Tl&gGK(H`AFv;)V3wiBD3(*S!t#OG{fr*6fl_Y~Xu$zX8 zSuq5^x~q7k(~ZbBn1cy-&7!9`%3a4LDFSJ8h1^AA|FX)m5B`+57u?+Z`sRA=P2U6- z=WI4nsz1l=JJydmQ{UM5Ci%ib&ftZjgGc@LF1$Q+L2z7Sko;$H#vOWlyOyH8-u>-6 z7V0!=naPV?WwK=1=8D{}aKMn%51aCuCCD|7jVpJ5dI_$XW<8XQmia!q7$$utNiLa% zewfFpyaM`rOAoaG_Y@^JNRe?(_C^!8#1kx?sNAqJcAK>w|GXtLfSFa)E+f8q;&K%m zeyY!C=3!LD3egfD9EyhF$<4!gQEv*0_{Uba$gLm2P zlxQh;>(9bdhz)n%V0ZEj9x!H0h^kaDWm+rq1+CNyJQ_$hWj%P!i72^+z~pZC)z;$5*iQ>KJNpi}2j&Sv{$gTYrBUDQbHXRvptMf5*8FaZPYrR{ekfAw4 z7$k8NJog-Mp3@RulhCEQK&XJgap=@D6vKq7WlMSnVmPR<=l>+`#zF%nN%UkI!bEN} zS6s4lrRkS|A%X7q!FD2p#-`*!nHQbWK}$PS=h$}S`fpxOe5=i8$8s85{1%hqFg)=G z=3Wn@-@ySExU?>7R~u{jtRiq#3xq z>b9wg)vlx+m-*q6I*{pV2e7N`PaaION%A#ly~%#G4tJq_?@?NQ;LA>rI246@E#cyb zGT0%eY5kl3jHGx9$MbIKScMX~vBPU|M6sF_3AU_4Z;o(ULEgY#2ltbryu(KMK@Xfz zy=J;#gI5<(i;VMmwZv%b7wT+EiHUP&yO+{uQIRH5vaS%w#CoC~)bT-Wth==lGGivt z-3V?waeC}t-b)>~d{^714L(Y*#)%au7iu@Og&{2s5}~U@w9N{Zs9x3|l$;_!%eC$) zcSEZ2e=zDdrj(GSGoN|7ga}3C+U!Ob^uUa(G{NtFsR(ueR9yR(SO4%TYgDfNB6t@S zx1%I>Sz&fnbK`shO71@SxU9x|BcH#0SfAJMtzDk61j|RXa@H9r>l&qH_8O>l+Lk4; zT!G0M)nBF1H?yP5)h(%WrzbH#%CoT;xPSRYzDW>2s*KB|B))`0X*F=#FV^ zbszbM3qH&mA*okd)^z8D81umP0)=QtsnZFLKIiKFMzWBHuo#{kL?@y# zH392!W5WIJ!LDd$qfPy9auJOjx`yr!`Ch>w%;qq}Fv2$FC>xf_nEf3}MX!vA>4IBg zY-3l)0r54As8wtP2Fjo$h|ry@oWm>DAw4($%g zjJuji455qA=d6snxYLxsw>+>=paK0OFu=gz zHntYI);>e20Cx65zhBSR#txd8h_<|KYG5i&+$mganoZcgX{4rRZpgWyyxL_M6>&;# zS`jC#d>!ZaEno(ubeLP9WUwv%mUNH~#w4|-B(0n6(-M+PrPaljbZ84;4(rAoXZpViG&x)ds zv$*ZR(K*rgxG(7c8ayx!Xph2^rbfYc>X^l#r?h*1;jNaKfV;}qN^o|Kv815J=%E?zhS-#Z zjK|EWW$+Fw^#UT#+pG!DPaqnge82?VQ$!hlY^h@%j1BB!%cI{Bo7K&IDM-NOx7`gSo%AOg+??TzIck0f^mDO*}*c;aG-q5Qj^9 zT7G$pI_EPMHf~{9_v6wFp+`jt(bk?#BE-eH3|P^V;)5xZHTuS%q9R0zZskezrdAHB zWfk`eP74HY9ZidHs^Xg7)uzH-uObqhSHLum?NIQDL}(nib)5w&ZA6E#_xL5x=k^^N znG5#ibu&#{X;$;JhnG3tY?-HT0t1-Yb($?qr(&(-J{?$|!+G}71=a5(8L=i{Z}gH~VW^flb?vXmBZ$aeQUD^*RM*TKj2jn`PWuz+X2CF6-}y9d55bIN5KbpIUI4qjq@bRlj4| zb4ckXa8G6!h=pATU#AwK^E4qGvKw~=kVvxoH_@5)Ho&SN@b4{05RgXqiqiHMOKe^m z4k7XC@zYtQhYOaiVp>)0H;32DcRn^(SsvbnnwK~~1(h0V!J9E*p353fi!+XEzG(V1 zHgF1LTa%(#-pyI@cPZR1OEiWvyea}>#-w%*Qi-BSX`mcp&@u7@-E#)ruGE4e z5h0AHh99wnH*`=WYJU`|^^F{$KeD|b5bov8K_9lM&ShTVE@#G>na2LPo_Wrl#i++Q z&Q>MAYI^?z4QW_zHBs?2{cah_(msZ0QrebT!)Xi=j?>!-aj%Na6SfnlF5bw(??QlDkKXJlQMYx+gE{z4K&{uhKh^$- z8y~(4Xj*f4q}*@f)ldA;LdrC?jYg6<#Xs0ydyVaO|B^3U{kL=K{Pjr9++457a|stt zl-7hJ*)zTgGXfF;VRyiH(j<3`3u+h^S+|t`D1|!?%dNq8QAp^#g;!H{GgRf@&1RmH z-cUR^P6w4-0ZTLL;>t(mQ&@(;%Py})tsBHGMpsZpUuJfNjp9r&6)sk>I>a8b#C&u2 zS@#RphY&uwQ5ER860T5hQ`ne-*o| z|7pwC`&(we`{T&&wc#iKMZx=DbdmihME?Il@Atp|`~Mg9U%;0C{Tl!C-_-tQ{?7@7 z@9$sW!n*X-nKZIWPtnK|xlIi=y=yp5sm)rqQ+H=D+pISvKcIP+CZos|9b-CDjq7zB zSn2e1PuT_fi|-PuL+h!hZvI3)gMDok6!5T@Uw!lR_{%hJo`uEJ@?EE6^Dl&4l|Cyp zV%pN9g4Tce&2_TsCi2EF>(Ph&ER!j|PptFbtd>!^yBpH09fwblR;J?%a#}8buF3oS zf4`os*%GsdF%0#f0G@kn^kuuVKT_}#>W=;g4fcLt^;-wZ>(#44e|M?a<4E8jJ;*6(!9PLB%fU#o{!>DpC; z=e;t7dLd|~Mlb`kzdHN(mOnCgg7Hh@u$B;<1`){D2t@ zFoj82?}iGGIPVuM-&nq}c;k(gmEgxk-|8n7K0YM|63NhatQC1g3?hDDj z{7w9S4(Y8aK(Y8!7vzxr5nzoE?NL32EZq(if+vjqfO?;f4a|-rB__A|y$b%Ez|G+X z+G2bgf)FhF{@z%WvETWzvm@J5Pah{cc^vS}$}+K7YT8j(Bzg&uLBM&3RM}rZXbjs} zVOaKNv&+53P9>5@&Hz_T44%Xrer^O9v(QX))VXV8dAL&yy4a_*xNK2})7m_@q&_X7fv(>S2Ef~kt{b0REum%c8bj^jIEm?66F_o zxO3o|p@$zK>{gz{IRM<3N)X*`a;lfm1*AV<8uG1Rzc)`?e)GK?F}JL+?E7WPf7#x) zQKFXGwzE1?2a}EZ+HT!{S*-Y|rTPLJ*EKk?SPDto)M&3T4*HlEWO&!mu<8`sGFZ2^ zsDt9xQJ{9ajyoS$%Ry2GH-g9A2JQriKgsvCN`DeVo)B*79_D9}Bw*@Y2J|LR7fIZQ z*TMZ;9G+@>JY3?|+rmn-z*;cW*>Z0trEO=`qW#&?SWXQR8Q6X%#>DiLIrih|9i0)k z*7l~iFb!Xi@|=u(@4OeH!5rV9rd$MB6pLAmmRZ#W23xgO($`>aHk)QGOK@MgF8B-* zaR&ec85}mh5B8~L8SD>BRCT;}0U7Ua&rafHTgaQB zXK@$7w>?Pcw55$oVD684|HSJnXbLLVwW`#V`y?HcRw z(&qx*-K2QQCHd7hP?@6<>D=XfiO%|QLdlX=e>GwNE+2{As48A>*-&_dRLWd4_Hnti zA4jhoe>}FqGGz;wd3AH%f?`B_R8dEfXna#d&fW(Y{WEp(AnU6<4TjdHM$f_6Zi0~~ z_#d#PbA9k_9XoL$KwXCka7NtSb1(AR@|h(awI?^t|_5F(G)vKK~yQ|A3z~O2QHj zgv;<8EM?C5L5JDQ2Lv0|Lr?*Z_iHBn<42N_aK4!TXWI#Lc&fc-n^;;A|N8T0b_$BB zu=F4Msz6>DUq4!jV2O~L<`cYNp)ql z%odS=es}{2EB~-${q7OCEdS6s_k_{>-u|$^$>d~5D zhuOdEe|rBBC=V4cUj#nw%tqVpDIA6D4+N}HNaqyi^q#w*tat3y#C%q7RL1Rj=1+aE z310KKQeM$W;eU)_FzHySMSGCwR`Vs0Od%|<$|o40?C{?Z;KyLl?qiE`!d(`*2&chT zxMZMEN|me&=_$6V5=2cRA_qigvk6(p(8lP)8Iy`vc!WAJ);#)Pis)nYP<0?B#-h zGNhhPv$&1TT`i9Vo7XR~eL;i0QakI*0p^A7&oC*j)Jd~jwdH@25)%i=F&MX4aQSV6 zpT4`ml+yDV_U$|*605{Tz{Mcbzq0G4{L*M_p9CV*u9fSESv}E`KyW>3$ZC~@(afee zS0qK3vvmitzV5qX2Ud>%9O(3LuIDaq22n0E@|-lI(hCNYO3yc@`=*@BHmV*HahN=4 zuy-i6e9CE~jZ8@1B)~BX6|11F8C<^KS$b1ZWp9P0gSuO#zH$uOi0Or-b{u}x3HDXc z&{HHqk=&*pXy<>pBc$@`fo0d`_pz;Ri{azOwN%-Zi6@ie_3+({d%(!mmTaNML5a`N z?JAd|JtUv9Esef>{e~_NI9uWFGV{eiho?ZBvdwzqhrE z=7WlxZM4?(D|E($X>2CalQAKxvjE9i$&N4l20n9YmGRSKZol(Lf`QvIN zBBknA#Z%Ctz!%7tSoimWR6nNE4mx+6+VLa67gJ_adc(wouIw~+BX8jK%nWEsiRpka zd(K7{J!ffcFgH>2l_k2|$;p}DLo2x>Cf$fVVb^<|-WR7)^{r;Eh0ud*>qN^pgHJVa z*&T}!#37{`_uevtZKT|lDg!&781<}&j2quo$(?|6GE3kXVJDgR7_WkT1lE}g^<~(j zl`UWbyg)UuXXc0`wy&aWq;>!;a1T!Fu34Hn_J%r%j`fe)-uZv9_uf%WZtcD(F1v^b z2nYzVAx*$SQA)DZB?u8BARq+DQbY(5kRBi;O9d2ZOX`vql@ci-0trY-B7GquQX@eK z1Oe#@B?MADuXo(L?>XaqcaOdI{l*#Rj{6P&QwMo7neUv>^Lu^;f5ACdyS~OghgLNk zy-3W=zQ5LQv+seewn-uJ^~x*}VEgpV;{ALO`^~mb^u)P3HxV_O>&@vcQi@Fqc&P=m zLqmZ!F9{D9$OfDNuu5jTqmOt0fhULii)&xFd)IhdJr0N-zG&6?NxX_-tWuZzN%*gh z8N~j8=X?|a*HlA)tNP?wc^AK$motFfIXiX{B6AvYS7bS9H~>%>2I=wpUth;HpQ}F| zDXb4`;#nrc4Xq;}_YO0GwTQE1A(el7!c8;kSNVpON@M^Spz2UZs@d`V1~ z+gSPVp~t3*+)oD5!&M7I-Ua+Divij`p+A4IRQwr#z)W2}W3+K`B5RPH% zgY%@j2IV8mC}9Sj)IF*xlq<(IDMIcM5pB#q{4)rdh8LLd3)s~dKQ3&+u^8i&%;4SP z?rx1}yegeQA_bT!)bAFae8Bg12o?=qJjkHY?u2l}@B7c9wJzFO3H%xuU?TT-#V8vfh>y7+k`S6bST2TtAca z?nS9yy|XfLjo{L(ci>>juFbl873oA&*#$DQcYXu)aY}`})bH->IJ`XLXTXB1Wa2n5 z#KY{}3*Pz*y5sI}Hln5H5wj?1D2u)5(44P-OMHsIY|E8?if_fsp5P)i(s59l(Uqj_VCfZ2eP)qu5?!8L#;`9#Rw!XoT4<hXw`)7Wk#w7`Fh6O~vrMN~xNzO+5+eUYaKOHnqRwCw$3w`Q zNy{cxDMp!O&v4qt6R}bMAXDc#SW@ z;fzLAfen@gmS&h)o$NzDzQrMQ1nlOA-(;vo)dftMv=2dl#A0;+EinD*U-3v^`~gJK2P&@N znTgs~n2hi~h1;`0pRmyfRK5_Tv@~C=BF#L&`mLYnw>VwP)la(nx#BeDTBr;0^}upb z{pVNtET`4wwTQJ6l0J4Y&&Aad0f=A@P`Dk zCrtDhz^ig_)i|MC!+Y9!4*oqnK#>JVyPSw>RIUcQr_~(`QpDWg4psW8_8~V+rr&M( zCF6PS>dWhrNygW!dKW|18V3v|=iliEEH76qy(UHsAwLa0Bi|uELpXB3X;o9P5C+N_*&6;}r9eq$P&PiqtE2h=jfex&-(mRAK>Q?gZyCpGr->e8&v(LKjHu8KU(@6S6`Tt z4;+$}!L9VIK+b3wz{m*!=FSMf9%9Sl=yZuN61P4_5NBPR-F<0I{?9gzBcFGhMzQ^j zJ}p7z6*m}vYMZxJJTIJ!{5VvmIV#hj>_z;Wa;`$nAooN)X2SZMVZc7Q+?$M(cSfc% ztp6+|_-#fPq!{KW6@6P^Q1y_eQGLFQ8!-gb9H~4P8^ zSOON-yZ`l{|Fs(b+8h6RQ~q@n{Oe%+|Kl}5>Y6vexjtM}TyX^0YKHVpm!Ou`Y`^u- zl_0-rn$MU|`MUdg``)FB<0)!)YkGadGP{GGD@0ce~P_knfK;{adjRr z6+T>Bl~z3C&E(Oc!>>x(8hi`I9}6^%{T7N}kIg&sU01&UtUMtpvbw<4o-^D7g!`%2 zM%`1HV`DosmfH3QCTeRFJ>fhd{obKB7CME_m4s8Nvk_LE%Vo6e*KcqKL|!IIG~#Nf z`!X>VK8r$mHdb8u{hvfBIk26rd25Y$oTDkYihtH<Os^s)rk_6%a+*1%PtSa{U*4 z3v5$v0k@#e4iH(bKSM8Xya4ckC*r?~od7p~p(AAN+ozQ}see`@YX&5-z=R1r9M1p^ zG!^!$;Cc?CElY$Z{g5cW=ZP3ctgqn3S#q|Zb<`SYYfniO-N{P#DC9@qKYyc~HG{Iv z<(kAt7(zJP&qC@%OFrN)2a`cW_qX7Jtx z!r?kA3+U<(Z*~8$ZqjK_y|rx2qx3`rUDBfMG)53 zbNI?QB$fpd`f=vWbtWtmgwW9FQ#oD%2Pzea!RAGj#kGI{`KFq8Q5G%;;I+F`LrrD$ z=DRq_4BW$57V#9SXA|HNWfIGZi%qV?sP`|)wmXvj zuFux)UwCxu_|D;o(g_0eOR%;6Nb~s=-8Flpy3YDqz+m>}a^EQ1n~dtT1bXO5vi zG&D>LM`+I&L!If?bgp)@N+%!>o>nQ7?6C2g<_H%evdz+`Sx-3{0=N4^egRod?jX8>GiT z+!{rANg##BUE{_TaX~H07KAtRVBJTo-@w~zsJ$Vo5X4}}u?SI>VeOy+-%#_kf4WcH zn69;Hjss-L!#b$RF;3w^&BVfVpIyVuAUUtjwVEPUFRowM*QoB;YgK0%UQ|Irv8jUs zNX9~N6;P|#K)m@lzrTJ++|H`v;)JK22RuJRCeA7_K|-B1?oArNs*S0E>^I!teF2~V zitA`W-!DlAn?w!AzeE(Aa>d;st|N$J;7?z_)~~LNF=~e9qlhM=irVrpZ^zLn3ub%(Wcz=~{CxYd6?STT9p;y+jX^(i-fsI+PhXfYe zHS(5*`(=N%PlZftSgN)YOgskT2-dVUgz^Er2k$uH3xJtzmlgjpq&bBNV(*-3{tJAp zr|>&Z*|?eXG}GCMN18}^#$!Z&Gl_c`tdY-n;DM~!8p;Fbpu*o=3D+$@HVgpWjA@e1 zyWr1{O1i>EubBtfGQmu$T4rWr*}TD`trax0ur7jF2to=r5S#knqj+foPxSUyI)(8R z=SklS#Qmyia!C&xrTr#xPsQi^UiRj^SKAgR)-38bkczU;xs~7;AmghORTPbfz3mH- z5cfHpep6$T=5mMApR9c0h4tCQsm?t{n=^h)H=<^lxm#9hxIVLOFeKIQ&8iXY@FoNT zU0zLL7=HBq$8f#GKelB33FQZkUE~@7zP5-2%x&o>m@DkrM%@WwK&u_vq1gza={v{Y z?In-oT{Qqn%@*I<^{Qg7+yAsd&IyCdb6e~^*W(+j22ONqc4VKOPIc=GOY~oi0LS~Y zHupB1S{O|WgExeD1l+~i0BhKEo2+`JBOBk`1^V)Y_pO2d;`R5MeDxtL2rfL;TMSr( zOpMI>O;j^NAqOnk9fSAD2`~H?J)hioM@}BHd>3o)bnYnb>QvPYM>U;2B{giqBI0!R z;2ZkAiov|098_1?#mrMH4|s+V89CNkWW4jTe#TG(vhMp231!H58DtMuK?vmn)*pK? zARy+)oZm9>DFaz9L_8kv`Gd_h!gGqpriV;B0g}cWXsN5ET6OW|Z@x7TPPlw=Ycr4i zM352@r>KqgU8Ms+kT6l%E{CFz0y{gvHRO>W!t-!Z{rZf~!}9cWaVU_FUc$OxW{f*o=B)pe#hoAtyn zDHxj1LL{%=%g**nWF|7g9hhC7yfT$8)6Ri&b1P*|>A6}aXL)HER)z;)(>4~)t{%L; zPaC!MP`N$ra@GzGm=fJ(X7}>#L^x=C`0RC|84+wj%E>2AM>Z370I`Jdqk_{UB5nb0%b zSWE3tqz%(h3z{!Q92AW}GV3x2bTd>0k`?vCm|gv zOch>8C1)luRkxB5xpu#hRSl`Y_TPH+P@lOKSL#djmxB zNbFAS?u?|Nrg^|%2+Da= zw|A9D7s`i^%Xcg+a~pVhz)=Qc--PVPN?~pyVvMpJZt;=&Voh`rMHT$sxaDuigu0LZ z=^d_l6@{xPMc3cT2=P-Z+1F0ShlxKC7fWtT6Bf1mc{Pp1JxuWriTd)j+JbTLUhVfF>%AcVdX{PX+zP&D&@}NFyVQ#FZ18i)&{m zyCkWgHt2+@NIB{XFp|GrT%@}2=h*8!pG$f<=G5ly`kNNr<8vK{-X^u(^i$WNS)x}x zgtZj%@chUfU<~Ootnnc&Z20@a&|<*Mh8qtrkL??i=435ULIt;2KKUo#aSRE~y2g_y zzAOAWOJo;w#Ds}?h)hdyp`7oHS;)vLnyYtX zuB>VWvC1eylK)iHZzTe_X;AP8F`HUnCKRKB+r@y6x9L~lEjlH7PE*BxVJ^pDqTXO2 z{B*qZ$v(4-MXuka*@9!-W7}u9+toHO{K%n3mnz?ga-83N!A*Yo8tQlZafySRnRfc2 ziJl0szjG&*s36kIV)vdS9qvnV!k?}SnX9W=s9oKp_8jNph4SZHz#x7ey_50~4L0Pt+w%Dr((hX2hmv$-1~dE%1uX zCMP4b>ZuP)*Oheyp-c?|Cd`Nz)$rc{?` zeJ~R~cTRWq@N*=tilhm2uM}q1MAl*yr&KxtB56VQF6yZ8rO9)5Kf%C@aCi7+%^s&e z3sV*Y4$N-_!NPYK4^@s1e=T5oxHEf@5q<{2{@zJvT5r$YE{!tD^#5R&?mnqW&2`UU ztQYt8knW4Ki>`i;4)F#swq%NDe{e^G+Uii_P|HH z={|Dodev1gKlP9C2g7cjJNMg%hcBE1RsPzZfpjk#E!ue8@4;gHq~#`qWq>whRNNCe zo$``D(gxWMDB3_zaC-noF>o}Q?`~g~!5CE1`7XChbZ7esHqh4mBV097rLO+XrU;%6 zd_EyU;VLTV`>aQ9RVgmH9_y``!V+cK6`+NUs$_zEU3B_$eM}=tDkfQ@S8s>z(;IEnV)Ntf^V0) zp(dgy-h zFJ5JReL_yJ588y|TDZ0zazFDUMmbUJlvYq2cK;A~pSTydcMX&rzJkPU$Epjj^Kk(M zXlZs>VT)LuXJS-_Ece}cYRJn+ms}#F?{~7kp*n79u4{2mH^r@nc)`|VC}vbW@+|?3 z?01LT>iE}h^dd%|vR`S)cU~wF%BK4%@v3QAv;76>{<(FkFtOzBm*2-sd%=pn_)5ja z4o@zql^Ir0&i8(w1w01|FyuWg}4J?+aznb+x!x^Q!jv@UBWwDSd37KvwU@^(P}(kKbj7$8pxMc^f}RX#<$+0V4_Z+ zxYl!!*j73`?3>!*Tbueq=EW7g^od1q<&#A7!jg7}9P6ORz8qg!8&h|eIm*z`Q?3>? zYuM56s#RfHpbf$?WQ`s`>r|bI!HvJcRoAwv;D;^rx6g`AxjX5LD0a^gG^jazyHy`~ z(@ct;@}v@(icYiS$9hH+TfzzMBY94rFNqSfzbV?8xHp+HZFcmvR&8;%I?l&nNr$an zYkQPf8O=;{N<&gj10yr@xGWD-LUH_{wdk$lvBe^7)U4L6E@c6SM;%`#u#k`x%K8ID zfy9Xq>L;Dzs1Y?x=ldZU z1dCs>q9QF*^@V@shO8*ZhE9t@)%oAayjcFbBo%PF%YNWMdO}##vLL%#y*pLBP*AQq zGkPjj>>c909*extU!v#oK{^95;oPtyAPL{F#Q<@*$-`_L*Yf?CKEJ2{`w>EM!gI=+ zXxo7rCwZBsF-P0MS;I*$P4Xjdn@^WbjDX}v&=vF7a57`vetItm!_ZJ!aA7fX8g-|r zbk3`qaG^i*#DO{62ak#g8V1vA{(5^?*8K(d^J0%!r@K)zuF5Nc?`7#s%|=mh`3)XM z8_{xXkWgM@9PtNDN!&Abp2G2N!>OT{dD)!2CyC-i7)j3VxcflC>0tMH`K4^msKfQD zK^2>~l-g)sw}DB<_@QQ64#N9Goi#&uQDC#Pv--(Etu ztzE0BLz&V=2b`hG7?b%yr0ae3*3%20oKiyur*@@gjeY{GO;_vc*eQIij)fl*FU6f| zJ4BUhR7g8mpC3GlKa37|4}HnUj$95n%ty7=uaA!5Ltmq_V06ZPvOt9;&2oVrC_7}5 z(S*()+OQRbCXG_NK0c7oKaRdPsnmQf?;A_!*}OtQcqnBc3SnXV^ig4H;a4~%qXK_Z zG=GYUm|PMkZvRvI&F)ozYl5F~vtWPzKe$N$PIL1QF0g;|AN#-lZQHbm`VWcctAKof zr-ugKVOy|D1rxHA@k3%>4EiB)t@X$tBn2j>-uxlaH>-N|JNQwR($1c(njaFO^rD+M z-gog!2R`zL#PR49QB0%F4~Y_RB}`Sk3gO)NA<=*6LkloU$2}v6b6<=(AA9?sx^4fb zhyAzjx*IP9Freqy9&vlhUI2={LST4E@`3K2B>zKV?c+z3P*O~D0G^nQY!MT&kAFy9 zlGhKP>r^k?{iFY%kGq-mOkO@o-vica)Bj@$tJP%O(xY@GnA7)R_B085)U|73@vHCXf`v3jT|vZe>JFdhdo8U-kw(RSMw<&b z4c0E~#oA`NBKFgmwCJ(;B(|S9RLw>tm{`Pf<-~gh+?n^aG!qV?nJztwlEXE-o7W~8 zf~04ivL*V|Bm9pJ8r-cNAik`7H)Pliv(4|auN|Pp5!LMtrxId!WEf2(7J#j8W>5#% zB!C0tv*@L`RQ)M&(@kE{uGSz=skjerROIbPB9tL@K(<0-QHj}Z!7oBcN?oB^}v?uJV&2@O3&`@6=2}cEez|)}v+_SOQ+o>0|G+|Pu;r8F`V)~Yd zAIWrVi6z8Kbfm&j1@aINtatgB;(1TCS4dWTl9*Yf83L9L0wMJ^EOY)cB185YW z1Udx7Nb%vtZetirQ4$@=dPuvNVB#C2E;|gT)B+hS&Uke;3VI_d) zf2oW&2{yr<_)93wldi-yAIvJ>8dDZ5&R97PSm#{5mJ@)Ay%if13M82Xt|Pqvre>B{ z3mJ5CGIgWxdsk*{HScRBqLKG?qj96kX_}J1MbAy$zz%b#mKS9Nmw+qw64)4XOOzni zfN^Tuu_uAu79}*~7fsBbaEo1MhkAxd&N|eQ{N`ey8eEp{ThUY7)!bx-Ua(rPkt{ ztH->hpF_3(D0p&=?%DGPO9Bf9ov@G6e~OSKkIL~(-tysQv@1Dg|y^BN(uHLgM z!sWAxCsdEu6(||sO|@b5{8q81zxPmymV2E|t(N(SEsGFNd%SZb?O6~M{5X$yE? zUxh(gVgK5wn#xG0p1;4>=e5w)LWNmB`SikskupJ95x4TfyPE|tX^XTXi`?8rt>Dhi zQFmGnjUJlJyy>;~Ly^_$C#0@?Dzu2^itzKR+XQ;xojyZm!Ggos0awe#a8B(tYJCbX zNt7ej!hZ5N?|#ND;Bos<{c(-QW;PFgPpS;REd_Wpm)q4Een4wSg)mosp$-Sd=^Wq; zDtk0jO}O+G#8`5@?e)5++R5zxFz&*dDm_;QDUuSZI{x5zDlX+Sq^u7uGy)5=$P8QEJ}7- zRnWqS^?bihvH+8F{JOVt{`)|`YiDBHvv!f%OUghc^Vd})z1Vlp_T(8X`E!#dsLrY!B zcn>tAQ&%o5t71OLA>+awq>al6^JE^QajzJZ zY<&f6FNo82&gURn0Vctpv=sPL#{=TB&6Dd2Zp~-YV!b8=U6XH`MEK&41BG2BZqS3( zNV^Tjp|^t%zWmKD(`-)}O0TOMU(2uZz>VF$7y@ia;Pl~%DtBR`6*deKY=(h`x~ z;XW9e=QKB@qiIkzdx(8wVJkGp&21i8RFp1gxPAHN*>{P4R{giaNuV$x(*VJ+ z4A;1gbr6Dr0b>FWs^~9_N)#tcyibzzf#FQ6 zipuJ{m$5uf8C;y~TMC(7c-wNhzQ`%}c3gSpao^$t1y+6GwFakV{5=xbBNpq^eT5~f zmu(%7MWQmR7|lxV9#{mlR(uwHxjUBO!rY%8&{*v1olT`R4Lzx z_1<-(4f15jY0Iv+F|-05**7-yWloV1G^e0jcIB5Oo6|ByIXCL!qU|>l&Jrv#k69%2 zr|La$n7KJU(kM4LtYaE6>zBk?&7G|^B%Qam30l=Ptb#5JYf@&{BW8a6Pjv)GI+B{e zlH3OpshG2*KO{Oe1lr3I+fuC-B!sJu(#a5Z%CtuHn)iw-2f`zAq-KP&IdIWqq5610 zJme4^iI3l)UEmBo=4`a!q|Gk9`SPWU-SZSTqU=P+RZt5f-5wx^Y}865ncZeX%tWL4 zu$mhuH-JvZ3NB^%SNUCnZNA!()buGk-4l|Ae(S!>5zEl3Aq)p*cXGc$b0+J3>k{RNC{AIyO;aNcBcShXH zQpD^9#4AV>;ItWb;63C>bv#{T4fiyAM8DzgY|r2xSZ&#Iq{TyG6x?l5?$DM$hrb-_ zUo4{LBNq3DXsxx{I~2v2BoHie0b8s2Uc3%bC-lkrfE-vt_sNW5gXw|UQiqZYb$Y%I zNuum|Bpe#<0eGc_=&}F?fDWE8h7s@TR_f#fJC(Zm!n4 zDB*q784nd-MU#HoiL5^Chiqg+#_`{P0^0{@ga*_AcaTS=ScW2~3fDS|RlwZ%47mdU zYL7nQ_`ikVWkF9BB133$AWp^FJT+)+uBRotqWVpzXCMJ^`C~?vnT{O(UF(SAdAF;B zmv5oR&vePan3vc^p!f=lO)3wtx9b}*SSFTx8QQURqO^iK9c+i_M$ds*B6o+Ha5*6xW4dMJ(?&~6*N%{7y@w?oc$}v{R`Z8O;+t*1xQOR@0 z)bfQISJPFbC!iY-oX)|M>kHE!q)v|(g)EaiK6K)%BEuJ@i?D!p#}1#2P=@#dmnOP@ zf&?_xNXT%{xJ^f_VSp6h)P-vq2b4*QXjqe)LJimX;p?p5YU_L|$kF#&oO)l@rgR%U z`p`zg_ITq^kz&t+^+tK^TM^AcuUtvz($nuwYFYOW68m8lB3E*xh)_k+x|#TzV5?9S z2(4mZ$~ooD2y0Uu~o zDxa-Xg*Zope?JLFyytn6uG&kTWN^mb{cJU0La=3nd7FX9LG=vzTYg?q{x&+5D0HNhkpqL3# zFau3WdGaC$>A#cqW26U#s0o%7f}cT?M-Qmli*@pxZ7ZKa8zkLr8FsbLE;^m8qt*^k z2H!%5$(!ZgLxtFCm`W@`v$RXeq*OLFg`AvVu^8nFEdH=_74k*%TE1F&frj+$!?pJ| z)%{DkC>VH4qr8rl7zuPYuyUZ>wa599;_@W{riTDLhp5_>#BpxU*W&6w323|+$i32* zje9EG76H&oT)nbUwqRSmGC%eRS zYObHTiZf-CL=S%h-AIvf)wVv68p}kzD5f}5`=CX{!3HvhA+W=C(+@$s1BSf;|MlH1 zwQiA>_sP`YMrMoB%#LV_Reun*2`ZzVJ{dMvz zsxY%A%%jGVSC0?GjUuKHrz2b5{8NNE{}qR-M>8TguAbFb3K4|hZfFS&05}WWA#U~n z`qcsaEkg1Si3mJj6F2+J3lO8k(A$7R$M*WN&YxcZ6_s=>4haJMeHQ=&e&3Xd9}-MC zUNPSRsASsC#+^rBq?BN6CZX;HklC?=oahQV+r|{V`-9(=>lCYqmEp>j`F--GsC_{w zTGz54R(e_e)7f4!9kMDWf8C5~!U0a@{FAU`3Od9_hu6*V$chSlQ1cc#DZLkC!?DO* zX^64kVm%Ye04x$tYA`RSVLr+W@uJwS`8x+4Lt0>Uw$bZMXGffw8;$lQ($j)|#EY$t zabO0a&o+)*>rujhx#4k`&Ve#NKJ$pTabVl{ z;t9WCGJEl4zq?w>mbgAEga?RD=C>9?5B>3fYRNX`*oeht!4b?6(aXkd0&NUT^ophm zP`94)3jpAMMtBsmcb#ZGt$zspC!c<66-aebf0kWIR6S=IPOV~!l}9pB4~o5l0vznY)}Cz#~A zD*V>x@+}5+FZUf0mQPL>vnLCjq5#d*Q;(Sj z`~PvPZl8fYWl?GuSe%qeSTkst!G^W5_VKSwhIh~bjHEe_A6VLnp&bQA0zCM&`X@Zu zOJ0TrqKwynLU}o5xOaiMnC`1&rmHT1nF2-1(R!yb}KT4RX0z@cGP04(zS=iPqp4Ms`t+P`Ant#w=vYdfl3+5SZPDM2Nuv@|UF zYZ&j7`T1@|9AjOCd4J<+9rIa3GJM}Ic2sUCc=``{#~V8x_Z7T;BXK~u?ftj3UnPGE zk^c=4{|}A=jD6$uDd94YzNkD^ji0luG>e-4LrJ$$ZWD`--ltZ#;;)8!V2P z{Z*!jQUz200Dqr#Uc0b%?;(^~DLwRVy5{piT+I11hbNWV6r)0Z{_-BE-HwgdJ#;tU zO0y7OvMi4F*;WmQf3^J9v*UbA2KZ+0$>&phG%>YKZm%RtIzBwObolk6pBVVmuY3QH zkk|$I6@He!)KBPN`OmY+mjTN2z1m|8UDaunQN{@XO`WTW1|l zZ`<}%?MaA@EWuI0Ji zSJI25(|g_WLl+wCEd;kdhzy18q)k)^ncC9*!#GAQ#8P33m!?&kke8 zNNYkxA{k8OE(4b7szSTZGn^S96v3Mp%?(R3le&L@9UlYUUU#O|`QGUY+}qS;*z=q0 ziwpj`(+Lvo-+vv+^&LoP^tFL#LAQX@?^b^z;y1D71gwL^KLzT5@K5ckC5eaW97~uC zKXardAGF$N!|f996|uX+-MQY)JbnNA8 z`Lc{VfuNZ6Pj8%)LQ3w~Gp-G}TI&;xGARPX>CvwRX^#`839GSdSbSeC^n1z(;tQPD z$A<}`#ohTkMTKA)XdtSPpRcvnBgco@XDgXq;%sz8LNcVE0lbG}2jm2nR~w$Ijm>&K z(?wV|^sP7eq%!Ou>SR;2>~do2?{69QlICrTpQonUgbE>~`QZ7jzh45I_}II5wbixx zOLIO%qTlUI_B1>E)~iQjJCLWckw;1`580KOC4Ve^TJ+Z+=YIuFUlrI0jeZU)cB(@- zjx4_3?iOlrtI-W?Cyw0FG!Ge0ACBLl$daNRoOjAJp-}=Vp_}=8IX7|p#mCN%m_29< zE=A`fA1egtR2qW3ZAaQz3`EZiE9`3^E8F!uFkE}m@8zE#i5L~n0aYVkYomz>xaqjR z#5LV$g!AIXs#XHISs$!|vqa7kmwRPkl^>g|aeT2slX zRBb%JIQs_|<}wm|sP;jb4In*q%P@ zd+H{|C0X|YIzkv6Phzdb2 z^H0?ZReFF#gV!Q_qZFryt^e3Sdc>KHivfdY0XvLFhY|$P8%PUX*wf^G%%urhGI|#xZQ zR_JpPU=P{k29Q=)u`Lh|j0AjpO2EQ;5g)>awIZ0(t+>4g(!(PyG`-qELw#v}F(lq3 z2>r>%e*QW~OnEi86>|nH+b4!zBa1vnlt;yhY1cS^bGp*CR;}7t(6KQD&T(W}t3j6% zW`)a7SzEs#&FtW@fTpkpt>Pd`r{BX5JM$EO*6}c=H+u#+Sq|`7lO*7FQT?8Ok;7Q< z<0P~P`LK}OfXDYkyQ2LxGJi-|4CsdLRUWy;{d?d^THXSUBHGDpZ^>(q9gK%QW2eKjjU*hmK^h8>c{(^UcW_=GJ!{1HZ$`xa1&py zc4xl)_DanbZ8W&h&suTEia)&1p=MXJU~`Bq=g!d!LS2CouE`6q$)MnBGs^@vKr}@n z{jT(|XRG+E2oE;m_qRlDw9!GnVr?LpPDL7@qr+XQbKKpPXKWaRYR2ohW^db1W)*WdX$1Xh?+=M=r>j~%%k_Zb z07C}MY^md=DY3Ug?i>_H0RXIr4U5rkvjiw&{N_O?-A^LEFfG*D&gdFfDx!}f02q2t633HH3 z63YMd$>It?H$C2Q;j#_S*#;`rj=VAYdXbEX1$`sD?N< z^!YkZ7QKtGUw=AKJOXxGlP+yLa3;?RV4z>V2(5kwb0pMf5~Q1ZV#f{-lILxLZIdTL z{K8u+%yC{^SGV1v!zoMv<8jhcjEz?b0;9{_FFwhK zaJ`%IjVrmQ2opFE#L-L0CC<4nZ0Ti$ms~ACzCRhm@(qIPX1tW?%!!}eR9T`}nDr(4 z7j&zuc~>=1#+W*z^Be!2Uc-AbYr#?AApSxpOSh@Q**i0-9BFoKGwk3fMn0zlA!Vjm zGOz4J;hewBU4CRJphE&YU z(?i)zj7y&Z5IZe|5s;Bdyyu6o%Gtlw`h@Q2TlVXnd{Y(+1Z$q+@Z-l~O;Xh$aN`GRNz+zG0v4B|s#c8uS_+~AiQ>JRt4 zM@WHHeZ!s$&-1TNIuDvzay@x3`W785-S5Dp=UqY1*48-w)g)inLK=u;{N!|_Dx2yO z3P%B6&#g7CF){-aZ*I>=nS_x{()e@DAM$oB`}@2D-%Xv)%^fFF7SV&&8OOTyN8fZz zJPyx*S>$K=6{fCJMXWN2FO0bhz%`Wq1tSOlm7 zD2gA*j6p4=z5k)FeGOJF<`qn9u@x0lfmxh@B;qK}0Ncg~Ukz#pLezJ2VaZ?vp&~yX zNYY(ym6kvow=z|q#F!z+&lijU0b*SGAL}q>U*oY8oJi0?=3G9Av0&IEjX)jz&TLN$ zm!}NFyP~I{(kAvKYr}$lj<@%{O`p`z{KR{Zb<#eKQkac2HS~LGU!tTP{2(aTOY?(v z=LP00;S_VwWjG9V)9y1^13OGp6IIY;#65uPa00MV{WB`irfn=av0lqK>9P1c$Ejpo z`ibjh+-)@6-p|{CU&8K!EFzTAbJMz@EB#ab&@Qh6blfIaK9gsguQXBWl&Ia*ZbyLS z7v3cpm#13G^qn1Sphh@l$!0h@oe7G`$Sv|Q>{88a>>H$}xvLC~EzcG`$lLZS=r0g? zxA4$C+(STy>)j0cLIumTv2W3|FuL{pKUp#=?aM`0uMOYvpW&)@$3BS--8rxw*SrJL zZ%e;t$$Rxf;_45H-$1^+2TGSaZqFb_1bVI&S^Cw})PlXi2&UyG5vAL>g!Rtl$F1OH z&e`q|e{dWM%((dx;3h@lrIMmrkGg0Nf9F(MQNcDM0dh1=Q>>1H=w?Vv?o!5lalP z3zsHDMf#g7bPiA^1WWUM<00RzU_wn5z_5M*R|eepFM(SB5l-+9hlGkTB%#s|iLWhU z<=3z+Spc-%2kg`-L(qTssUW63z~IyY$g8*wU{3HqJf7ti6|^OZ<7@noXn6Afm4}mF zv^%;3SYO#(+`xO5uo%>{QXuk35$&Y^j3^mx5m+Nur*Pvv;^}CIm%jLsNQI>Gzpx)e z{q$Pwjo2{LzXhS?&R|$h736%^YFI?RTNJn9&Wx{6mxH?bsLNyMcT!mG>yhdV_ z2g94NH@I1jQa7mtuRUkWiYK}pLeF&gc~629IAS*J53CaBNj&(3ukxoSg)Xp3k^35H z7uxdLK+?`xLh z&DKc3$_qUpdryPaP>})cxJUICuU?}~?Qm)%sJ=1&c0|7(#%fYh5~R$xBVP-cve9X+ zEerl{?7eqXlj*-NieteFq5=v?#zGSz7K+mHQwIlPNkp`PN-ZF!4WyX8$jp;CgBuWgG znTO`-N)&IIys|*Ifya7%ud-A~U$F)^K|hXc9tYBxPg?c}UQ!}!CC^z2EL2BY2=^odY` z1uduHjt;}_rpW=Yw{Gy5_|AbxG#Q{u;}4483_=-G;Q_?*w|CGqc?KDHp&5X18${RJ zz;^;^*Led8VQKR8Cni_CUsJTi;s!sj3j#5@#@FcH zawWfm0>SDfW zPKqcn%4Y_@Xa4;5-&f|0W}j4&?*Q^NMd9)|1g4eJh=` zhT&0g?lGDM5+EO4lDwOMEXIOk=S>g{Q#_CkdOly};WGFY92x3`oG}wCz9Bn1&zGGN zFzZIi2;B%bQY%=>V+HzUF?~~GgD&*%rCcIEqm`!A%nz!Gs2q3>xLYb|2>jyp znxLnjR<0Eo4&*F0$jR+j4ZL^rP40S#n`0S#Z<#}^**!I_cURnV?KU!&m@X1aPT_&O zo7KTN{ODgN&vo5B+!ovr@~Ca#m|GYzzU}5Myl-6b*U4C=Ab5K2!<4D2GU0Zwo5EwF zDKG@u1oC=7r06H85~pJ|e)>lLiH-sn#SPDmosr!$QGTTegJxI9R=|saEghMDeVeGG zVb5;!OJ0QdAysY?vq1Z4qf316-RINxLQuV8k(>HdB&5- zS!PR(_@v98S0Et=l7#2oSLCLEjEZ#Jc6UdCXioynANmo(7MFIycVXbxiSry6eta8Y zpXj$iiWPqsqpcbKOlR~06N4QH(Ih{TRTCg87u|Mnv|CIch(0!-b)MbD;mBkfJRNr!Y)4ABVAaT3b zh)+oyCIDv!xR?3cyTL}@H3cS65SPMcocWN#S#%~y;^Et4a3MbKiy7^bxnTp*z7PXC;vaUn62f<`xp);5q2(5>|-gU@ZcP?oN7@p z@Qy=8uq{aZi)<9Bbs))>J>}A_dTvaQdW=liJ?C8OkAsk#hV=kFm$7cVCH1*$T2Io46f7DZ@Xg0FD^9P|}x+=s+Bs zBPgxmw*k4*0EZXFitm6b0Vg@FctsOacGU4h)3OKV3w3y4FK+ACxj4Y?aV^Fg~nZ$%4WYqk2i& zolXr5Gx>n&<9yS;l%{yA5q;=^fXK(r%?d^GTi2-8))QnMmuSIw)iUWNwc2U(&g6I% zWL+HAJmKXkw82f&>o&OH>ykc-Z`IIej%Oesav+uN=P`YF`~W{5KBR90*^8O&nn;OH z62aM~imelc6+S-d^b$ZFREf0y+5^whmLso_iq`H0yl}IDg40m zJln1*u`wROo82(?==$T|nN$Do$hiJriDUa`s)H7D(k23_Q*X$KyjQz(GU~RD()@wy z>R+#Jjjb?d_xj)sCJ;|2gBTwdZlot?=AXI=tpSDn3-2!3*sf)ZRol{0dc|z!L`pUF za*^6br>Nc!Jk)m6s=iBIn@xf(4?Mg2tS~z@m(tCS(Fz3gE_i6?Yoq= zEMUHl-h!C8ewV^w!9(gjRdqT?ybXM-cqVW#9A4HJy0yD%rF0~4^Yy@A$KQMTa?BVZHz3t;Rl1JLnBlyi*_%>(- z{=+8djlRl)NPNEu*6814Wx-HeHhvTHUn}}wEBarb(f=Rc^#*!Xy34k!l2KB?1he4F zA{ef9!fc=px2z$A+6;$$T~_rgn8jDXp?(7`XR=NiKNu{vW=NFFH%ZJ1r^2bTIi8-2 z9w#|bBl*kdv)KTb_d_1>xLMwvKVFdB)7C>jWt@$Kv3 z>bfu7UCL-+Afg{H`vq$F-4(!zqH3Hp)&yiaUl-Yl>wJKOa$L^@Y;lSYZT&8F#B3YT z%`WW%Q?D=!7BOv#I62;I42cC0XXrbSl4HJ9Afp5umR}ZSi<<~$?YJLt>#|?8kxsr11KlJuYjNd2P$7*nkyo%`$ zW_UyP4<2Nyc&O0h=F~T{rWUJ;%=`7#^N(LD9q8lU9Tn~59qir}i-!sQ( zBcfoqkuu-);A;}`7&W@UhS(d{LZ{^7dy6CsLx}5Oax|DhuE{G!YVYH1yay_m+g6E?1xqPA?t%{d~MVjEIcf6AV}v%2Uf zIbwf0XU`2Mtx-Xi)^z=+7j^~(M-dwjk|oFVqkT|CC|&=NO!?i6n~QKmu7O4b9qg( zI)Q(drp1pfji((0w*TXUt{!^lH>)b-Dk4Dj)Ck$NKJRGKrub;Sb(W&JvlG$2_|7M! z@XY;WC^}4Yy7&{x5Q&suzIetlmtb5nQ>1t#fAfnvcWldC&A)_0tC$sz8$(ZiWNj)$BEQ@Y-Ax{d#~s9;YZzTiO6t?)>dEf6*jlPH zcouF-WF%7H)qP)ku2Ms82VC{)Nzv%DeypQdK3k@3U1g(JSc|PNU+OZn7U&a?=^_U> z`PE~h8aE5WQU4ZWPo^ilPCIi%b33m^&@4{=F6BRvh~PP;jWY!~JlOBg$ISL)WM|Ab z9#I_F-F(F3(790NAv^l9Umosz9^f`r`h;|Zpx_Uid+6rd`Iiv+enAjO(4Kpc-@Yfd zb%f|u@%W2ppRQH!)aMcsrpqRDO(Yp$t5~&uy7m{QvrXjs_-$9owd~LGuP?p#>Gb}2 z?zZoKzC~`kBT2={hI03K$nXnI-DuyXft&>raDyO^|K^qi7Uz**DRs8ugXCi`Xf7)R zTO=pYVtFfVqz1OS{9WpdgY3Wk+gJber?;YQz?um}&sK=wh#__l-$fGpip~pv0sf>X zjhjrD;6bA>up7yW|F4JK4$jT0Wkn9b_?hKvVD+2@nLLIEX(M>x3^>`*mMy!DpJhrM zOQN|fZRILx8%=o_U9^G@6-!^QZFy{T{bUpQ^`kwUL%+CPHn2`^;oP<8a{TiO>1jv5 z{(1TNE2~$-0<3lWymW0#{mPratuNPb?UPc@1V?q{pAo(=xtSE;vw+|sBt>uuf`i)lLi#;~sM?@#kWTL5l76l zzbSnsMwel2M(*;GC+KbTxNt?Ionq2sF0n2uNgTwm5k4fVoJO*m=SPV4dj2CF&DHv+ zXA|z{=WCHg`tP%>gwq>=RGsqFbIBa8#$M|^-BZNAqpMc1gvs3V!?rqM)V0hg`b5+( z0F(a{NM6A0=Wi@tFo*^E_#6UxJU!+!c!(op9Nkm(Qf72VIQ65d8TD-BxW66%lGg zS)q6y9f`5Yam>FnN-)&tRu8AyUiNHCYM*i8Y8x(g3oqf`Mb0KHt^18)bxJS}pwwd7 zmz_L6f&RVzfPp$+HUM!&gn$(}}C~bJL zo(TNaHI|XBnvt5%ozps<@915*8MLge)~8(a%F%Id2t_?qW?ZpSHM9_3j7G^%O^(dc zeGxGrYp@+YajJ6=9jgVZ#ys1Rt-k26T80?Kj`F z0In$BFiSt1$RfxS`+o>TxZ2~lt>8~IPB|vl$ZOg?zU<-a)QkpDj!Bmf(ZO~>%&M_&>0Y{mrv_Nnui;KX_oEpPnd`Yy`q^Z%i{_)q)tpR27Aff}lq zSc+T)W?8c5fY9^Sw?P}z{y$z~ws$cOwk59^|)NDGB0B5E0n9KLdU&N!5h?S-ee9PRYg3+EpoLU44# zw1+2~5SlhX2M@682V~jt9duQ!bsk7bZlI_cri$FFF|}ZAW6AzDB+_Bcj;-$@OPXtF$N5TD`uX7 z*>F0i1Zg}xSFL;sH;N$pweJF=gpOD^;3rQ2v7?0T?b%*xG40o^S41vs|JcW%a!FNZ z6gR@0X#Vqjg6OZBqmy1G-p_0foHe?2PX~^SD|OhY-`w;dVY=@;udiiPSNN>R?h~Ca z>iDRuUS)Qc{i#A|oOJQm+H*a1u!?K)Di>bd^U{jaGWx5T@?DBnR%&=QoILQ2Fhlqq zCy#H1(f0aJ{{+MfErEEC4`jp>#ryuugP@KP{-pWW!jq#SI7drvZD7}U;8x4rpVK{E zZN4As{deR9z5IMNjVu7<%bmK%vaWlxi=UI=vbL{YwMSg44n!|oRiJ2mN!s5lqSE&F zsd0#B!Mf@+)oSlcgYVzuT`1=3*W4N_ID6#0e1T@4gj;^ZCxRY17+xQJu>)UAe~VTC zb-6O%r2^3hF?*GNh`CtsM`Vz7i32ZHOl2pzuEBNzFT$J{de@%2E;vi%N7z)!7%07JaMbsd({PG_lw`G{{Y*TZJ)nODd4ta zWr2;7Z_S3?&=|r#+y$hn@+hN2_4p7?3)tR9Kd3jg&&xdm<>K}uu9p}vHW5_WP-lCu zIVJzb)DyLAxpS$O)<|+);2?PukBE}}p?J7BI_l(j=J)dFXUczn(Vz3mlTkU*|J&;s_RpA}TNg_c!8VUzI-sHJ8e(<3hMvf9kM@vYNYVK6K ziTU~IEhMYynJ;#Q+*CltlNL~q{ubb4nY(F6um^cr^xtv&L>B-&FXQc4PR>LMDaPy= zVB9{vlULR7qU?Q8nD#dl7%K&4Gjy9WqAN>?3OW9=FU)XRBOITbftsJhp%DXH!rwc2 zutgzHnU#}5LGiU&^j7%eX(=FyewMeIdhXZIseT}NtT?h);K z4&=S1$x@X5qVVXC!?+i(HjGkCpHF|6LIvtX5s@z04KC=40CdO^5a(;A* zFei?bUI*X4rwq|~-~`WSrr1oq5isOsuu9u7CP?Bo18T?myUkm&BkCmSJqT zTsN!gqOC33t0~1vV|4vQ2>y(wtL{;$e_4%XG2ZjhyMNL8gg=t(5h(*`HeD51X3e(Y z7BNArh)A6WRv4F`2B!iCqypn$z95uBqx49y$G2dNlMb!EFFP^9lM zLLX{9@NqI6?OTOZI$mAmje780r<0u3p|Gl}aJ}dE`cGeUCUKx#3P|j&6{cB%SpP0qI3)n1}>>DzqG9(=dPsp3P6}ilL01ehnIVH_et{5?BizQ(8<-KD=FNx@ug(f zBJxY%5)8aiL$hPp;h-HGFhoK^%EcTesJ?UQ!u-?7H`V z&}iX5B>e9!gW}3U@9k8X*5K>@!TQ_xkz`&gjO%AN$WEWMZZOO(=y(vIXfV%1HvBfl zd|&BP*RU%pF7Yf?FK^uN8wvb~|LKW$166b(24JYG>=H?2Ts#3Rv@(oJll5jtMQSCj z?C3**AToqJf67L;j5T>_*^T2qT$G|@NgY1b)bNY*!%R)}RF{gn+QDyY>)h3SB*y26 zjo&4PZkTNJlQ|Ad2G-_}mE|KknFsW=NyjklZ(R!Q^ zMXqouvOAt)#RBao6mUQDN~kXZ!aqiCejZ*Q0M)-nV^6V9{~k0RpLYx0FmTaK@8TO@ zGmd?FY|p3Sv-QJuwq|{%=l%wWQ&^hp6H|zXy|vB0f*}|dKR}T1Yqm* zr~}sz+a-bt4f}Wltq>)A0P_i*O!y-nJoo+pi4LHLK7Ko#4USBI2JUA=CKPcON7vjJ zQZAsjTi2Vn)Mf9>%yE)@7}ifhFS1nA%01lt_Ul_+UcEG&V%U4xc3fjTJnCNadb3ua zw%ZEYNuJuW)-Xj$_u7DtLTWU)HM}Un8lVm7BE@{bw3yeu=Ihq|pjj!iWgbb6@t51_ z5KI^f;=#iwu7#L>p%|rPx{MhHdmuL$V~P*M8&=F8s4FV)%-!sZbX{HNLdVKV>+C>U zWcak>o#JX*VBMks1RZ3Xc(Neg2^C2@Al$JC?U%=Y$#c%IVF&t(!-NBF;^H4#f}d!6L9>g-cKl=dezQvw za2uAVnTRy&f%O@5JibmNriy~7gtlr6U8t{tv?|+*fXLHI53|ZAuic-p{nK?_JFYP+ zsH$@Nr0Gy;T>c1A%OcZ9*J4&QmDM;EmdJ=c`e~@v>K!@SIDBq%6B)7q`Pe8J0JMb| zk?gRU3HAVm(H&pH&?oE$a@x(#4HDX?4S0&FSi{rjftXg@`41COZ`Q=&)zm_jdXEkztdE8edTNxY>}`efzT-ea0}mG|GM3`i$-SQi*aS(WPr zj=W;+7|zc`DNm6F)S#zpSN@&T;(tj#{hvpwQ$cj3#ZSuvb)b3?wvQ54VqOKBCqN%l zz+C!DD@s3haZaUTwf%&v&xt|nH}ATvZ7}tWav>e|M#|-PHmzn-OUojT|m(4W?CNTAJ~4qaa0(5(CKB3-a0kwR+Wd^RMonO zJpSy;N~4{pxND2FDr|}9-TJNiu*0f=$wId=0rl|3L7@xQ39xyA$?0@{4F}Z%FZhOW zA}4kyQlEMB_#SeKgVpf*Uu#yWF~v;$ooncOGI{0t@qevkHFsxENrp;%p0o{BXto2l z{Cmy=K2honLkh?ee1Hp_<||4cin&Fb-~@c9F)#u0$3co#sbCkd0gYp{u3+87rTDv0mB!d%C!=|P zooY8A9dysEG$0fg{Nk?gQMW(uj&Ij;U3UR_&bJ;{^_S19kPxAY*%^Xg4-8rJ=(y7k+rMEg_g&jw{B})Jsdcld}nS-T;*g1)%@qJ&RMamKQ?HM`EkA+8pODwM-e^Bv{MaRXl4gssL!JAADT)rC^Q={q*HEq~W|mCh zOMz)vx{=G`AkY0RqRz03o*+2@z*ulu5C#GHAUoTKMG#(8w-Gvy6W;~a$12|tjk4|Z zJ>Mj|06ZxIS^7Y^IcXh_amrW@*Xswb_VPh>T>E`MQxC{}LMxkl4p9288M$&2=};bgGXR z)0K<(-Rz60mR4JSf+R8!tH^a1?f^w) zJo`BuOwxFRj{qk{T z`hHA{%ZE_oC}Uy5@-jtzGBgT$s2zO}w9X}7xf&81*me=QYH9wyiHLM}tQIXRcRy=c zwQy**(=uo_rs_7(mT?oFMQiPnJ*R~Jfy}z@MP%^;p6pd6yoSkOLAs!m?YG1Px_8=9 zkvV{8la64$_~C7IrFTK}17zltbhnQ-m6oh=C|92x->JlUlXmvZ0XjGG>ex~!MN(mMR?hzKWcTK{IYO$1WSAC=(1 z@=^xWFMUMpl;y%XQ+^$h;fuHNcl!>rPl(HCr$yHc4FuC#fEIt%vU$vxM`(j6&S$s< z6lx6nec+lngt5ZV+udx;s*o4w#ClYKHE(5~bFz^v$frE@RFm#qRwLKbM2#DDS;P4b znT~nGIeEFl`lUj8DkHUWV<63I2Y7VM35>T-H&jKubYYt(n@d z-@YK2Z?=}dy>Pip#_o{kk>w~ohAqQ=%0fp->uZ?VyzJ2wkv*wjWb02?jJhTE1ncAn zxZT)a03YEgYygnO>C<5EiY=845kUKiv}C%>J(|{pdI5jmEgi+XjdV*>RhGi@Lx-`8F)g&uBq9$P(U8k8|LAs7Rl^KTBN z2k5jcsDqnaHLZc`vn5k~@gM)I#pkSvH#_CxTZtSWo}&LEG!zXQuetLrD$hPQbSVYp z@6W<25J@(_^#tjrR29FRmg>2ibI&_&#<@uGvciU<=q|4nbAm92lO>!$?%^rvo`$FWZL0x2nC941bbi)c-N|Dl=>SO zG?&Jc7yPR<_^9cuDm&%@Xwb{yQqKoF-cVy`4ToZla9lj|+C+#}ceecT%PUq_8WoCZ zJ%LP6hR85A8dcLl3e(d2FW3jqy4bma+y5ksO8rt9y}@B{n@U6{#YMF3l725`-mlZ9 z44gWqyDb;eQ4k4|`1^-wvi>wC9(`0U8h*csSd8=F5g(WBME+VA3hyvk-3nIo~ z{w1$RO}truV@+8pK5Y{Qk548!@>5@MCdJAYJcXpvcMk_A$8FfQAsvy&f2XvVSrCqM zJo{7sG&0mbbEwSqMsqSrOF8cNJ$*OhRgvvTUBJ8I#_+~7b1g`GVRtO% zl%P=joCPGBNn?Y+ULGIMRHOv+D!LGdanjH@$=Oc;owbpI#vTcMrN106(c~Y-XxofZ zwAebk7CMY}G-nfiUtr=bs6$X)@^M`&VvT}}abwmUDwJCE^o3*uLRNStypB~86C|3V zZGbt^1M4^>La|dUZvx@`UN1haYKE`_IA!+-iGry9Hc{G^wx?C$X*Bz|m67!X#jZ`)=jmfxw>>tD+Ct;)!#_eyg2Jbxz3wAfqIJVaeQ z-gu|ErOUVlx>9Q|K2&|`{&U$F95~5uy=o?hRS;K7RB+veYT)$97Ss=PFr^0ghks$L z*&4TJUE@}o6D1$Hp~e+Hg1r4x2R43^g-d7MK40(al|N@8 z_iB!8sIPnH<=U6ztSX(U7WZEUV&4PbrL=m0fip9afJa+I2|8!sLOUDj&`#N}+3GVH zi|joNKL}QqZPD(U-m|i}g0Cc9gf}Q?i;FHYbS6)j7iJ~ksaKy0!`u_jhg?%M?3m#YlpFp}VxY$|o|8rTliT~|td4o)b zGykV67XLxXf+$m0JeS*9Yjd1d;qCXTRi#zoPMl!c_{ory<1W1nH?IIC&U5Tx7B7@G)deED(daVFl4}q zz-Q)i7&y+N@5Ng330;h>=@=H_00z>|xR1OsPzJ=`OoAu5@ZnFEP|G?Ztr_Zp)6wt_ ziCT914N32C)fA_u`57l+ow$3XpwwRPc}8ZbPN?U}oKB5;pV6(umoIhklQQ$H)JjMd z4oYzS|m9Y!`MbVFhyRg?HGg4;kC3y~P^r3!@b_ri~2pdk9kXD^(? z-1WygyaL>>jGE|#`<8!mi!Dw3ZA^5j+ivJ3LT(Nm$Qc~^>*d_7>m%8aamS#-lMhNG z+OvZ*b^4Y{h6k&ii4}t@WdASRd?!1MnhF^ zs-QXLaC_EGAZK6&rp>RD*y0uNA9eSAmva8=Fi$AiV;}{F;;7&UP5Gb`2EMnXK!O*C zg;?nr3mWkY5*3N-mg#AVRoggp^YC4hNF~ z2kScEF1&)VcYmjsm!OZ35?$kc=KFt_I%IYfNPZ$%nBL8YJ`Gk&u08sjQff}b&ZYQD z^Br1ca||fTPlr}tVVB(Wd;@qXIi}l(-3my^bj*6TsaAv=0Btx49|QK`rE&dqRf!b1 z^0sM^G5SEG+=L$-k5i9$zL0?W6y9jsLHdbT@N z>Dz4U=ve5ig=cg@zVbpTJl$p(X2;x*fe!U+7^@F{9`In= zE3gmc9b5)Shlfay7hlg-3iapsJI>;|3Iakxf>A4-r5ZhzQ{+J%Y;{^5$D`$V{{8U7 zzPI+CY4HB*b3~!+o+~4zwoV=Fb7bVrlKIgBqZ?oI(`U;rwHZ>1)0=pW-LQ|K)hL*Y zc-R+2YyZak9xK%1FidP|`N!)`;1erZkTh#)}VOF(tj> zK}ow($`Aul6moJ%>_db_s^NkCy^trFV2F|1(JVWUx{Z8hbLGp=)$}}6!BRf`^uQa% z#PfwmF;VS*-D}prm>hqBMX^A}ZhhUmPu2!XbiMt#Vn9yC6n$q_zSpAui}5tU^w~NA zWRa3M&_wV6sl?YRa*dw@_S(!xguRmOA~&8(D%Jx;o8qfV21Qov6vOU={@Ht2!UB7U z+`M+UZcV9H%W!C3i!t7W+}CmSSmJ}Bj-gbSq;_lPDrf4MKhw?@a1>?Gk^S1gYy?Ll zqX?e)ysoe$&sBepTk`cT4GuRPU1p+*`(>+gIH72!Whm3bR`cRrrgL)&b9f7VRXA` z#OYst7TPjpw&>~pao(ZtPVa-0?pX;XskdS*#FwnklibJO)i<57=GTTlR>_|CbV1V= za?T8g&U`tNM{#Zm7y>uY?X!W9Ygiw!VB{^c6g%Nhl+4KmUqRREc-2e%)Mv<7XZyUv zUj1-zDQWaYVH;Lj?~jFi8aJ2kX*Icc)V1S5*B8$R#GUq4myC%FRU7JD0Gm-uZi z*SDXJ*KgmW;g<%lOQodHNJnb~X%Ed0VN;($IEsWhdGF32v>)aN4GFV4F;O1S{^_W603JZY@` zZO}JLSx}SfGQ6yyVP#94zY_ep+4|J^+7@5?ENlBO6?+`A1?kAiW(i?VIhmu6d1n=F z_g#vy{`vm2oVXhA%Y_qrMMc(-J) z4mh2D&hzUkxb`-(@$p$oG_PTm{RxCz;*;0FjWR%TiU)6hCwcc=bi>B@Xz1kM6bR>7 z^;z}Wbj{+_OH1~e>snLo3}3ALuO?+$Wh;)3%Vsv3JyFBdiLWUI8=G!j=SWIV2|7(h zeZ=K32zl6o%UEjGmh^(9s^ zz_UZ1So?-x_vVd4&g+UI8{g0q%?X}L*Rwng<+VnLx^91Fs!doAFo=xxswKJ1yCj9; zhURe4W%U%B31~@k>!cT>cu95{ZC{cBBX&+orY6&D?|=>slKwS6N|WG;;EF&2eCT=e9W(5FH z#F0G!9_;7VQ!LwXI~$wC4a-<`ApfNCrLaNSxWnycyGKMecc=Fs4m@O{W6I6E2|{Nm zgG#gaLucL9w9g1e+8mN==B)9H<*EbdsN4W3VQNv*lS&P>*jrB+T}xZeZ)zMGq~+4P zHs*Sx2(NHDd~}@2PF6v9SD_xG9t;(Ow=4Nhli3it!0Q5z!a~yQ=-9x#SeGlphMuOO04Xd(~eX2-i8Wv$sL>Ho~;LV_R%Ln*D;-^h59WD z?|ZbZycgQeXO=l8-vO;ol)gr1Elq8?2F|`XL%eKIbg5DPVTN6A%N!6rris-PgNn+# zvdJ`EI+#^VNTcrovr&d^Q`v!}{Q$gcOQEjv=-CytuFl!TWwo4}jrCIG(XK*W@5UQ$ ze&$~j|H7JUmW>qI%i#lVAOjm37G`^aVz~-CRM*Ai;znyLs^R38$hy#2Tm$n(#~of! zpo0uSf7oN1421`#Kq(Xb0@?@C+Xi--dvHz#rGi{NAND00Cl zwd3ohFBYZy4NemCHAm7jBQlcR?F`Ao!!{+jzbgwAkVb${n;}T!(g7$7Bo3zpXkEoMHNKh=IF zz%+72sqe>9Eu_4+ao)0EAXxYorFxVSDeurcnB;j-<=>3hA7XBjoneW?G z#}>*;fhmC+siDe~Q`frOs;JztEY_sW(PcA+K~cFovib4E9ppaU7sm^F-SpZNCo5mS zd4ed6y)~g5#0wa7e>eBi#cFGzm-51isQq9hspX4v_(n@8p5cCL8mJN4OZp){>7yW5 zfL?w(E56+{1mTo(eNg1f(K&o=WLanW+99v16z-?+^GNO)%C(z?n)k3B7|Dm@N6(bT zlUxn0v#b;RKmGg}+zhdeD&-EbnX^Y5%WVr8#DHe6mXce6ZmLA@%5Pg$#fn>ARYWiM zd8NBVpD?99RFro#^6Xe+cFuXD-kp7vp?1A{B$edk%5lA6WJ&HrWQCqkAH)hg_u1-) zE*16#q!|EBeCAB|TT_|g4uTSB{Q+U&5?*;w3k&cZgdDQ@P(XNaIi;cbjtfK1Bf#Zg z*WBq3A3N{!x_VESzv>wcopY-EgmfsdAP1Zenr=3ZUYNb@d+CbTgJhSDTo(xqpO-t3ZQ6?Ukp5T6KB{=WhQwS56Dpa2@JX2r z!4n*3_ev-(U_$7{^CTX0YZHWvY!XUkx5!(v;vJ4uX2t33KOx@-|07)EuWtMK&ppRl zPdzPsV_JLZ(hu|PpYHuCN51bKtZcE*&p55ZFTYUqVH-J;>#?MhFH5o5ho@NXSP9&)XN2XqDZ_GGlQ{p+FyX!?nv6pSo->bJi^=>~@X|AuHVO38o zPM^=95(W^!9R)YDNt~s(-oZ~DJdbNfcz>TiebFMlV@8F=x&L?j&no9moiZ(x;;7s? zlX>-((^KoR-409gDm%5)GXKcpCM!w#xKC0BJxmT#JGPA-o6tkPaNTuU&iV?bBPM>g z<2hE{KXwQN8|OD&&Rq*u_=4BP4Bgr&+GX)^zPIVk z0^bdkEPyfgHGID(T#9j(hrgNp$hzhl%DAKXy%Fkt?%hA|6}^71%!%U*iWM@1kXJU| zQS$kQvcYPVbB8-dl|w9Z?X;hHS$TFMoO7HT4^s=WrV29Vg<;I$WmrB4Gb-T|z$xcz zT|aS_WE&_1tTRmb3>5JWfkGO;Hcw0I5$r{wDdrlBI`CNEn3U>(h03(6;O z2WG%DxeI(rN-5Tx#^1j1P~dfDm~t_k^O5yh0Ys#XdCP5S-Yn(7=+hR>YL!ZXlLT^r zTjs{CZn?*~xzvE*xI>QKyXIELSDGH&n{rF1Of5%0tUcqnpbfTP%{?gL2CadXYoTom zU8v$@2ybAIgG(-Q5ju!;c-?J~NsYE?ZD67DlX}(+{juBfB>s+UYVJlN#gK?p_%5Yn zb^^nOA25fuy*i7=NAROsA-v3Q!e{O0FNpxk<NwjDybtgyK5>L{Q3O^G^#VC{EA?M#2kZB-=;pC>9DW|L23{@G7-Ji78!zd!UM zH#RWtRlWQtYq{7ZHt%BoS>>=lPa20xen*jiTh=y6bl45kizc3k+$s?8YylPJD5Fzq zM;hY*$_B<}pZ6p?5jU41!u_D`z(v7C*CXl68bA}zq4Tva0qo)uM@)DCst&f-N6e9HSU&Q~L2oVNM&b9z4z7ygwAUcAC9O<{udp>A@%0?9Oi}Js96qFhI5CXaH zK!`J#w@(xe0;1D68}NFQjR+S5jF0PBfdW`Nv&5c}K;F|EXcLWM0u53;WaBg+e8ksb zxX*iz7caeq?Hv44*kED>&x~WRpFV=I?*9wMcEkJ(C?2X^2>z)NEWZol-u8LV8%I#r z_-6P^Iptrk=w(P8?C_6RP6E#fzO(lqh6?V$OM36xzg<(AQ}gB3o)&28F)!ZC(cfE~by2n?{>Axc-~Dc?!SN4BuDzaMQf}%{@zX1@0}+D4;ryWeku(b?e{`sSN8MvbpsUd9wQqzB-&ktKkBE{TD&l& z%f&s?m8I~y@V^I}E7$Y%69kZwKS2TH*wPe)nx@crM{S z)mw6ga}S!EI-I~n=7F0gz${6gf)VSXb?y`ZhD0>=oPFuP$3c&ev=DzM7cYLup zKK_D&4_#{oSI2Mce2~c{&0OYwJRxC zcX`%YHtFQwS|@G{myQzdOir33LkTl?W_KrwEGyu}NEx53H#e5-kXh1;TUm7v8pfJR zvTC7)C_lBccOHq?>s?FV^C7xuurMP|n1&MKDYGXOge*tO{T%KX$#hm_D+ z`kKF+$H77OfS{7Jg=SGf4^)G%{py-uO}5g_Sg2jB1@Q5vnh+1uax#@Gq29 z_(x|(xeQQ7yH^TkJFpfXt$2$L82+Wv{7JCJiuabNe;8gz`RGe*%>Vv+RGfI0d?viw zChm0OjI*Roeba2toS&O?eKU$MUl^N8aq)h5FD8gpcXd z83uZ|8B&yztgsMz6n&*bq{~Nvj<)f!E~Kw9cbnj`A*b92{Wios4PG}=1{2BMW6Y~i$c8aS#{fF z&#&`t!(t=n$}9Ct7ZwFgJp;5;7{@U(>=Bl0kK5-AI*=R{=F;yCNMIznW(hQnCHz;I z8`_C2QZuZ5K4*4}psH`W^1=f6w_S#e6azUY{O-*SX$E(Ey;k9l=nXtcI@+ES9Pp`W zofMOK!!*yk(ptt^P_r~;?b^W4w#u`)fNxB&z}Htj&C7$F&p@<(nLyLeSq zN8U6D2x6Bi0UO6vonmk2^( zoP{Cb6Hb@27JICQQJa>UDvH)~KE@~JsIi94D81vf0p*%J3+Jxm(H#dX3Q2JJ*%dA| zpuR9BjCyy4p8F9j9sxGg`fAF^Vs+-w)Ff!Zbs9ruW5<`K!NStEkD@ILiKQJ*@5*M? z)8nBUu4tN-xHa~eKCVi8Q^L-QCyh?2&b^+vZKW5I6Om+sPC}LZoa5@<;K7cVbtY{! z;fxw1T9E6L>+6Op)s+0zjnJ?)ZaYz`y!Gh2la1A+^R4-lTN9|}$sD>oWCpYjnb6;o z7$Q&Zo5pr3UWUBI{>q#0fJlgj4d@BWG=(LYY_RGO=Sv`M;)8+XGhI?bh`jWI-F0X8 z@qsOr+A8I0OY>iv%C>0)xOfs~^tS@F;d1qZTHZNx?~`a15}$$=LS*KHy-JETY+D>G z%Nm2j{4}obP`7^IoA55M*H)@`ukv%db4bg%)8TY^j0V>Te;DQoKrE#0$R9>LhcJFO zt08=|NEJS=&3P-T7%%mb1CexHWJZh?`u-rF+3xIW?x(Y@FK5-4SPm-P=N@$qWR)~( zI3;aOV%fT}QD-KZ zR_(Sndc|z9S=e<;+CPRNXeE+_E#yxCNw*psIULmi{R-Uk7;taTohTl}oMH#c0ia&~ zS+k=BNkwKgJ}k+N;9;Hcs~nf`Gk(D?3r{prw;jTpU$&c)j9wk@_y`wEtwZ|-Jibb*Pzlofo#Rf`|_OU??@u zG((*>GW!Vwl2|RDoVs`9mg&3N*tWB0Tg*68zq>2(;14&kzatI=!H=OeIxOX)bnyvc zBpipELe>Llim^1!;AXF2oZQki@0``f;BcKkzHe+?U;WlH^g~pq(`$K$lF~|h|Gd`C z{gOVMw3j&>z*yD`Ule!*BnYTrlbSPQL7h>JWZPz9Iy3-EUTFFZI7s>C;hbwcaB4bL3QRm`-=GQ$*O0x zJ=AuqD|?wbx%EzU6YkB%H(Gx(8ST`|!0R}c8)}(M25;_)2IiHkoE?Y)8Tzz#2kXR? zD=3xLLqVK(Kj2ZF6x>X;Z2ps+qBjC~*?yArKEGLX49CP$&7!e) z{UjrSLF^m;8Hh90&AWU?)bq)|!bdDwRTo)S(l&;>+zFNzWOp%IN zUFCRXxceMlu>G@dQCm;iVM+nAa&i)OQ`57LU^eK!Ly7c=Ox$kLuX^W6jc{9nio z&)oB6D74l2B!M&+zaq}l*aH9jQJnXb0^b1;j_r9xk#9gNV?>I~R^ez13Wn3sj+OV# zMWTS}eR)s^rQcy7%Du_${@4-e)}0%=m+I!cy+Zdv&eYc38LBF4k3C>fqn>A+>;b7P z3%E#KYj{^2mhFhFmUgsQj;}~1_+Gb7-%5cY!vWqv>#>jf!28HFFzt=@R%6Zyvwe+D zlnJizEqOAg!%!{Ewe+?Cfef#JFf*`+f1#ba^DcByU@#oK;@m%QO?!GJY{q?<))A2Q z($gDtWIoi>p54>0tMT!SeN@mw`R?^H>i~;)E1Je1##tmQY5k6_?)J6#1<%lcvZLy%s6(GAX5n;LPf|WH46_ z+J)M6x*s13zN8$(h_9x2ah^3dQycKtsKd}Vojv=XWob4N57p(CytA*BahMe^chjEi zwsKpiOm?|XyvtQh!0a&dB67l=*Pf8p5Zn!;Q1)7^kyw%F4V??lfU)5J>!7}Z|Gwkd zF7++C-htcjH&Qg5J;-F*SXI>z6oZg*A6dlRm}Sm& zoxIWokMuHDL$HU^U1nZc#pCw@zD_@o&8>dY zsBX^OTF{*JzNdkQj-Eg|WTvAghHD#6C|}OZq=!QO+FgC#_vqh30AT(9f0I8M`tJ~& z|38GKe3v@LR9n@$MSWzLMAukxI?^Q%4}7nhEyh%KkkU^-p(gid-)tc>_fm)4!W$R~ z^n^_K@E_T_{?CUb6%U&RlXTq!f0Di|!Cn(u8R3;|5^IR0VakaSiC zg+CL4FY}jO$nF6&I2_tW+yaHbIqY=d=RKurnQ?$HN~BNUni&D2_Cd*Hopo)rmqWx4*@K^7jo<^=BuH(bn{Wu z#$x_$V46(X9EjVou2I?jnO4jFrk3NvI$-(>%fPv}r1z%M(c6??QjUZx-AvAKb@QyK zPfM0%GW*TdV69Nd4KWcc29{0VD*s?IV4Ge zGT*P%E33dLy^l95stvD1cOZDp5e4CwAc=xYoRurCW5K<@P#T*aX+n3ltPGCV)MRP= zvg^>6Iojz+I`gVz;yvHiLftrGR8hvyrGyqjwpY8H<9&{@9o8Up0VZV4vuJuWefm%A zv-w9xp#;!EVC_Y#x`ayyb6#*-bYjpCwB;~HyeK%%JDj_sQH>5~uU2z3So;_B2VHOZ zm^KU^Q#jywQHNihbLQ33*+{MX_cNXDHhP>cBAx+)B2l(vlswv;_H4sGBSX5O-0eAW zQZrrDgvU6YsQsuKN5735?`TKJicSgca;Y6Ya7n?>{N}_JPStAg^e2g}9%} z8bgK5T;q1tP~>7yjc(q!H=Xm*r5+p=Y5{!kmYrc6Bi__580`bu09T)3|9%wB8bX z7cI357}k5aDT}YE24-6`OA;JZT~Y#lsGG92!OCc|t#EV;tD%maWHrp&&6E9JH-u0% zL3KImeVl4Nwb9qbZDonR_?y68_y<_4{8Cv`0!7fDF|Nby0!YK~LnZU2em_^{6NZR4 zlGUk(PFU80%(T`}u!goQ(oQ)hpU~Rbu+v1@ak(5UMIm2x815V+TwH@(xAq z4*Fy+u2pQf6k2DfWO&F9@xyy8-HgZZSoawE`0kb+|G=)+Le5q`7tR*qqi1<;@8#o? zbSF|Qoq4K>0=sbUH07$P?|6s=isJ1~`6A}oVR1vB6qBlzLmw&CWNo9@v-eEyU9qlu z*BF#&ZhDR;s7+1Wa#8+BDPmj84qtPmt*%fPS)YVGfjq=Cqr)#{M>2(tPlTSpbvZ-g zT0Gc(z{Zx`lv-P=iBD>gD_0@0^Iffq7C~LBuhjb-;nny%E6tceCAZn?&eH@F1B#ly zdH@hQpEB!P?p7;TWG(fsQJZFuzf@KZ%JFfeI1`EZ2$;+hzHnDZASEno`5rm#mrC0+ zBnW4(=sU!@4V`Lk9NB1v|1$P8@#?Kn9jnmGv|-&=m9>{yS3SbT`O=GWKTe*0Bgpu` zsJv_)R65P9r&KZS<`28mHGI{EV@!H=a#}}spi6y9SZ?l?oG?T54Pvp0*p83dfkg#t zV%ekf?fH?r)?-FCy8X@5`DTu}uAq}`9F5`IO{hSCT4Wz9p=JyrV_hjxzc|;=oSM>9 zzr{P6=AeG@OrL$Cx04HqkEgy$5_ZQ^o@`u)&kTT}owwBlp)=%-d}N4RC_AnXo) ze61r3wud|^$DVD?%wBHQs)oHNlSAntIl? zG&JHuK9rj7%{~Kc?kC#T`z0*2UXEAW)i+^vw!r6s<7$0LP?Coa^rzN>ftYfNt}Bz6o~`^eR+ zsA*c_ir+2E7=mMocevNfioAYIui5L#iIwIFzZUBw{_nkcb&l&Uq1dsdz**Q{Y}+}| z&jk@HI?bgfx9DhxI4xk~iS`E&qjH{NRIEPX@zETXP*0+cfm?MeaeN~w0y@}v>xSl3$OD%Hqvf_b?2GO?MKe}6!fSn3ywby( zm#}sw$Gctw(Hfku&>fxhiO+kEtb9{kwW!bO=yd*Q8SKygL{aGVllrhzdFg&F^9t(g;8yi_ z{CN9L$8yQ*>lNfQJKR~67}2CCOmApx`(D5O5b?}#v`1*9IY#@*6bP9vk=V7LD!EBp zKk}TCBMl?_cSw(5pk>%eVNB$4j2yr5Ca<33nYcL+Pm|-VrHH=gC$%?ekxKdS7b02t zW5w0pwP<&R$y*vSBZp)5INIu6v|T+Uiah zCwE@MDH~+PtQMc?HrF3jQ}v7pqJ}R9S;rWpuH#zA%*jkQ1t)r6#QY##0(x8k|;~g*A95m#JJiqD-u~z?EJ3=Q96^*Z?eqiJX~9-a{5l^`+~zGg3oSK8G%-z5B!Z^ z*IDqbOBVb3OY-JbL)E-l^FEr=AIOfBq~zP*mUW%!y7%}!iws##+J#1r*zg~SbTBX~ zPo_&Z>|az#8!a^n9!gbd zP!hcgv8C!b+eTN{`=@2NxG9pDJL|6(E)yCvnd6H&8$PWR;CI!79{b`6-77jM&>Ev1 z0{p4K5;UAWpYU{y&4WJn@UO6n;2@36?(Bp#Vu2;j9pTDPzdjnQpeE0BbNsx=34bm1 zh^!;yu-Vt&CKAFZ-s<(a88g0)D_-l(gyV~8@FK_cFo0}{{$b|$xZ$Kv^>%Yu!{7(J zMC3`dHXBfAl(}^FSbV`ruJ*$qLx=?5=~C)Pn-LlF!JxO%dXAP6m2NEW(96fWSFYl+DY8MfvjmcF3qI2E$F@86Ii z`vyd(KkxaA4z#`7X3?MbY<@qyMA|R7fn_9q-m`P}uC54FKoDwRBkr%m2FVTjr7x`h z?B>loX+!%y5C3wyV1R7tcSr-pzIV zm#`Tj*A;fGoWKvTJbveSE6$BxOMgxoQtJP9HfKTiz;8b2+iB(@KQy2H>7`B%vNhdG ze}S>{QIWAJd~jZrFoWBV&b1reKuDrH+C`xMuv9(P4{4wpuaoa$Hwc}8ds*JA~cnx{?p6TOr&wHBYar2N73ZFf0_2Mg0%@Tk>o)>WLHNtY$N!F zi)dR*hMdH}xb;1e-vK106>r}Qs6@8y5DhZvMcV^#H)}11)8?h48*ecVGq3}Fg)ghn ziv!o(49$iFiiPN=)egH6?TrVvthxe8J7WL*@rxS6$@s1cr?3zC8(~X6B{}Ca?enXc z)_pZg4HFMqF;xQ=Gqi&(CAa>6w{l}3n2cC52A$zj| za_iuAYas0G7i3qKS^ePRy(|%_LV)sfItk}T;Fse+@2MTj-bGA!;pMe&k41uGZwC~J zihIt|lw1dPf418FIX-%gixVB5Z58#og&3OQYz>|;zKPxm8WTAdYE>E;Skfy-wrH<- z6Zitryy{2ymx5}n+ZCpk%lOpR>{1_da==RnPW}YQAuI}h9OKOY1$qqQEzGBTX+IqF z0!&)m?|`Tx6@8P7!;$fl{L-TUlB7nC?Y%a#>_@gTxf2sg-eSDb?aCM$7uUQ3Z*EQ` zE1R3T4(6$bTTAkqCc`#aYbWm#2su9JR)!zFHfq-cC}r0G=KUq&I7WQ;Cv^BUv4_RP zZKd$$qc$N4dh~C=`2#L?0}WWJQXLWMob{o#Zs_S;+fj0*rMOy+&dOy8y`g=f4<0Dz z(SjWPdp$HKh;f-$4N~tDzy9=~bUCkCo3SQaS~OITTJo4^X05M}&8wDR+gu~%1ZKj_ zmZQ54qJC^We#LFq`U41hq*Mshd5Csg6h!=c2JJlN6b~P_vD6HRM&Me@V3dPv#xE6_ z6qEJz>fOh^a|rpJO>+s#CBs+3X)4_H6f^5UqSeF`3;3iD0bc-A*cYXF4~p_Al&mEN z!n%erw51EX3EE&$f5-a5QX%p%&sL4C5Mc@JE6}-GoSh=xNk2^X!+in%$M}+Cd5QwZ z9LK28+a>%;w-NG6*ecVe^3u(U@#{}E$XRo8Sk1A-=b;uya`RMAG@GMv@C_U}t6fo$%V)}(?6zt+KcUIHPnr;aZJKOyo$6vC4qVPRG^MWqA6`x-I8Uo zMAZMn0ZZ$iS_xQ(VE5Qr{}W9Y^?P&r|K-2=jWZ$?mzk)1%Rral|-v1dW;*B0`te{ z-fKA8_k12Ni7f_Tq4=)_=A~eg!DCwFpj4j5Oh19U>&An{Q&@Y@fjv!`^f25oVdOr2iCmcib9D$HwJ&LMZfqbpWpT-uc%c%v*|yvlNyvXKC+Iz;4y)o!9oKD8L6h`vMsT-ubr z<(lI6A<%TUK?*zuD)Y!#Ww+BgD}jwt%e76ky5czEu5kxj`|h6NA;UsPioqzP{(hoe z(Np5Z*6(sEjcu*rR;Lt0rOWM@rqa=J=lv#gQOcvlqs@b%t1GuRte>Z}{|<%m7%Rox zi5C!Z3!-kSn$1#hL(d@|y%7Yu`N8YoyyrgUwumk?aW5ld7iZiXM(Na8B2u~ck}&li zw7vJckwfn%7{usTl`~#VBa61l4rbQFfwoP_9ucQbj}qPs$iIGa7Pw@;;ZWMo7bZW5 z`YZcz#H}BTxLAAi!f(deh9r5`^{v{#*)64k@$p>;<(FFYe~7r(;QxJY{>IAxox%D4 zi+BVO=HDR(zO-BZUr`1k_Lg{GTQabIQsr{Gc4D#NSXlCr*GKMN^+U}(Pf@miaQJHZ zcaqX(*IuyW_fT<;xddB+n$E0sK$Op2&hknGis%xinfk%p`bbVI;rL5LxH-aYlR=;I z8uL)nE|Q0x&jgpG@*X`?3`cv7(~5H@5VKcb*tgLN29a-!CFST==~lAi%7o=d zQ((fIIv0?RJl#warcKh4oNDJF^=rTZDAt2NLQ}^`@`t(e9W1FxEsWZrK#DWL;$Ome z`p>ZT0wV+c2#i|H-6|*e=xqjyl9Zyh^WSRfDu`DuX}lTRaV-AU zj_8~*YY=>LX00d9KTq>@jRQrvg(m9h z^Y^1~tsH;ZXqn9ksB?bsV2$DR5kdyeat^R?^dJD+z|D`1i_%q${K$^P@hmwJ$t)Sq zp&Y|-k|N)X-CYiP9lwM{gWO}`jG-pB>%6yKmVSfisAZoFyy3hiWsBmszx7(XX^W?_ zt+{$?9;BZ3CS#<6iEU0wMipn~Z&O={H`=;>s$4HO4-8F9y0(qDV71vWVfc2(k1f|@ zF1i3bbeze!7$aR7!D;^O>aJ-;Lr!!~aUFk`Y ze;?^I<0;4yodryBS2) zs}GzNXCR~d?_e=8|E@9Ae|0c_hq8T;oq&Ch;nIak1&RnsT^791eLCRmv)cq{*fzYWYH+A`Qhc$Hlbwq-yd z3)|>A{|t~?5FAkRBC3RD{&nv^zA}F|nE%SJ?41YMUF>^AJvej}w_|tySlDDd5}lR#Eg9|yG`tqng zVSa8O%JAm|H(8G}L!CcS<-EO@%&K-UBucB}dvkXiI4Wq3Xtxfx6y`w1`Qlq1Af;;9 z#u95$11x&F7DX-pd}+2H55ewa1a z%c>}j+iW&q{4;*hRhXNg;lg}-SZxH4i84~!X%!TQm)L~s? z%S*h}Ox_TyXS)D|W5gbmE;03!bQO#doeaqBXzz0#Qpn!8AcB{QkWlbA+jw?B@UnZX zb=X-mHwi<uJS3BDf@>0Ba!0X2X}IW@mZaK3@g z%Z^R&(gO|%X)q>5xvfy6B@T?`)*(sm`blW@J&0>#fzRS0-GCk(SxQ zhLEh(u}2fRmd!3MBvqepCKcRY8H74TwBW?w==$v&s1Z#v5ukIA=oOHJ9&Y0JKRB%z zOE#l+B?VveLfcpmYtgv&othN67_y7duhabp-U)sy?^K7gQv&7snvv-svS}-h=yM+# zHkpW6ywG;^1`~h2ET{7l38ky%O<4#&p-V{%ue_dbyc94o-pjVqrjwi|??u)NeiY`@ zq(lP{N{>MLloLSfcXZ$n>1xNb>g86Bvf)Y2JyGPVK>!zJolC$d@XcqeP77>C?%jMe z(;e1DOok4VoR^^LS)cb@m#0h$me51+A8U}-cEp4^U&p+Yc8u()wC!+>8%RIsIyo)l zY&E+1)3^qLKCl79X#6qqFLnFRdyFA`we3#)Ud&c zp2JbZT3~NQd#ImFo-`mg-pXpJi)*O?4}@Gx)0APeN+8_aE%35a_zhy|Qgdj1bNI$v zKweC)|3Y58@rAs|;@WNrp8^B?BZLxmx}ZtFLn@V~FU$+_JBc;`a|3a7qtB(w{S*jV zcyJWf;&M#OXS8F&LQ_*%F#@+LF9XHa{LQ{TA^5q1FV2H=U2{$n+Fz}1l%C-ec*!0) zW$32rm&)4hXLPN#?za}IC*8QDThz4hAb5G)COui#)_X;D)XY*p z91+R#e}Qc~4K+lYvE^3GfXPf>SfZmXiwO``!ES@%tpvbavScHtASWV^@_|I_1p{&J z7Y*{a-w7bYHNoPF>hs;s(A;8re9b*F>Oy$U6Q$H8kJo2(@|Z2fK8>v#3v~-Z&EjEfn+4QJV8}(RMC?MafNFCB<0dSF z-3~|K5OsILPGTvF*~`7Rc`UYe5>3%(-HqRTm2bmg#Wc|hiTuho{PDAC>kPZvh%3L+ z2Wy;{I`pGn#a$lRl(#>nYE3v{dh~%hR*D&5ZjO9SsB-lS8YS2JZd?5Fo^(QGCYa~E z@F{F!XnUOuo=?8A8L&_ARptfK;adYjYUG6vki#oMqy(%YR80`XzrdDCXn-Smh8z_< zM*$`U_H}M+2^+bFE}jiM)h?XeFWJuN;|pWYQuG2j3RkUDQS%=07Oi1HPiI!!&!t=Q zQYe`PTZv)rU(ky|YsW3Dj9ri}?yrCu0cHs)1Jb{y7?t>0cIh4XMTPk|V;RV^g9 zxM6p#M1%5EgcELe6@7YAv?|%K{qNRPEWL~%>`4=&KD9?RnWQD?_v92u*%Y5c4kiY9 zwbc5O);wuuuc-(XI;u=bA|5La%RzoniJgiuV$jny7b*oaD})e zBQq3x(mP^bJF}o92b#~Zx~r%+XLaFc`Y3@+Px`ffOxsZrI)5#zd)@FSUnP#^jUm01 z3cY~DbpIspb&FN?9WuF581XpAaShdEp zJJ$s^`~zhe6yK_B!8tA#=1KY%qu0odEf3`Nz%F!|guD+_=-Zr_?f(Tp9lP6cD2^R~JJVVPn#6fnGZJRq6 zXM|`wKHgZaX@{bROso;A!anZ-_D`TSPRzV;VoB=S_<;TwHau+d=RLlD`vv!T**Gxk zXZCN$E4WZ=dG7h_T)I+^M10*FsHDJvTl^Mn%4A(VoFY9WajyF9q_;t4SGP^)Z*!&e z2IVNAiDYIPqW2fb4<+XB+fSxBGhwSr(B%{b< z>CIsi8Ns%ZgW+N;9$fpx)=6@DKK_Sfs++zO6XAmiY39jwN3QDP}+8I~&gI7!$W5TLHsh`4(G( zg%{I2dfb8FtXpVtzET%LRX4|I5x^c=YxZ@~DyxamnnDac&^DaGd_-%hK&=*Q>N>Wr z(8i$Ggc&qRbX+%{LVZXxHV4(CluEwcbWhvBNxtn;52C^0A$Kh)7;%KZIMXo}X7;<$ zzUe=M;1U-WXom;M_`}|jI=sfgwYxn1e;43%&ojB&BcYC1=4CoRON&*wUe@uXaU?f` zl8!W$*saj7Ys~zK>Ucr8bS=4P*5O9O%4!!f9N4y;nj;rBx0e&9@y9{`2)z84zD-Hc z;|z@I3@JsP50rnr7`ooNX$WHm7$0c9UzxW&XcVV;V~mrk9<`QqmwRk-Tb7j z0{$@aN7wE;WLZ*gLdI?R>)t2}o#H-Qe`NVsS$eLO@6&24Z_%-hW>a#}MCJ_@g6f@u z)E`q5!l)07!zNr#tuDUTJGe(+D|`x?F4!|*(-nGnX&pdS(i^2Ik(SkNPml3vcy_Dv zQhO5TJ%6UsM~WR))8VyqpOI~zWo$*JlZDT&H@W^9eYS>WmwxO1#(ldO=Z*3{j;Hd8 zkz|Ah(MlEQ08H;)w;%v5IcBKwn#kGd`#yU{IZIpW=0nk&RHe!`VX*&x3zq#(JFaeL zpw^pIJ2$`OhtJNoW5U?3|B^3+@lSur7lzUQK42I(`S0_U&;KP~iRGFDGu}VVSN8lZ z3JRRHoKUr7TEErrZ2y0ZZK90+vMZaOU9tX~6Oy zF2MgXUPfjgJ9zpLfLVBgo=g|WfjL$%K(PCovNpa_Tn zw%>kzi>4}fruS%khI598b8&LfYDwN?PK2E^iLXjG(KSs&mX^2aY+ISA;B!2!T<7BY z=@fW3Tpn|Puff4VFhB9lW)LYNXfzY4B*hhbxS{CMDHocvRkP;jQNGl$qu4rCj$|93 zi1JqYuC<<0@WJ`YmgQB^c&P6ZO)102Az2lmAU8AK4-E!64Zd8aE6V&(lJ~>ATl1P} z=B=2OknB)D%Xj>aEjVuq&n2<5K`=kQX`mg>oaZ?8@FB|C(wm|z9{?fsI!#~z8I#^p{w z@b!e_W68x9h9B+kCt-#|19FpE$j-=<<*1F0zyB{$r7h8i8{k#ZwvNf}I-_3&e z1wuj~%ZU6=VAjfS12bsh%PvpxHV4v<5NBfa`Bcy(iNurZaz8z$U^Vg`h?Yoo>W2l{ zOkoc3Jfn1PRKe;n=HX>MM7W2)f4NHIy&d}oYwl1*p_N^Cds>XsfOX*eWCxLMgnGBd zb}Gp-fOf~qK~633THsuwP2R1!iTXk2yA-77$EJFlWnFwM?Bp8uE@E763j<0Fc3lv1 zDT$4c;sPY=QwRcdY#SfckZ(3`ggtfCIBOwa~ z()^SnFHm0v7;Ev!GaaQ9-q>To@C2-+D#OTy2e~$~i90+=if>slyM~gxmcOiwCYahg zxO-WUC-wW}Q|)pyPA`R9gjIOwtsGbGUHwp#*=3n;nVwl@Vt%80&|IgmSMy|Eaj42W z%GltD5JCEB;or;^|D-Sm&OlP?{8^s-3|p#gEdeI85>yu4i~kCJ#hIr|d+Z;yboBauOW?Yqly5=sDwGFrT6{ zBz<0xqe^|v{-4Si_HV-2a1fTX@PE5DwwJ>q%k`|q;_D&pcxlXSer=^I()|c`i1`a| zVau=FCv2>`{9VuOVgQO{{t7?YRMT9=>N{GB_fY7rS{{Dahw|Lt)#*G~Y};yLk<&t8 z{gO6G9n>nZ_9x0+yw~hIF|HgOGW8PH@(FZC6v$ra5NYzur{SQ56?88qRQSXQ&I=J= z!bOE5PHadV?775G(aQIxG7J>6Dxdl^b%tptWp!U&HH+2#Yk4gmz0x793wQBJP5e{M zG;h(a+O!2}=&)sr>L?1i?}XbFZ40x>vQD)|~Zf!F%#0I;QVTcfR>6 zX>SWPuWXkk+RM|q)YsEkZv-%T_00=pSX~H;>T-4odcby6%YC~eU}+nG8^@dZ;vAHm z9i@T6;ta%K;F#XM!&+inhsK;y#Q3{Dlb+_ZhFH}3Ai8D8baiqn_Uavib++=a_Q)1v4|$pNfaE-T-04<0iyiX}peCqk6`>3X{`Sxgoob zA+wS2wOw~QFK$cl#^?YquoM54NJemoKe1~qu;51&FMv}?m$AllcT(Xb5-+hK^p>J5 z=s~|@7?}V+(FI_kc?R))#vS|9PggwtAn~O??dw-r68(AJBb6307pd~Tm1)89lU*kI zuL@GFN?a??ylnq5-(2~@8SU6zH(IsfIHo~u3G}3(kAJijX6gXNaJ^mX_!3M~p{Gf% z11sb8_`{pG=%p70>LVC4A9kycInOW7Z|!Edv1NOxzD986!WLC7TTaj2e&?qV>DAF$ zpM5ttN+;IK*DrQEwRj#?y2BY=Eg?INe^~K3z<5MlIs5KGqw{#zW)t1IIn>fa1p_|w zQ7k&J8zzsD;5u=nUTEW3dnnq;$C$HgZ4haJ8<&PFL1Q`h4E9HPGa4L;mW*J_HA()% zjbPD8TnBTL(on2ee>wZ5=Yv2L>Z0BLGeh~;9gCgD#~o5G>Z^x_G`FTZ4e>s?seYFd ztkx}=e>D)1`SLWuBQn=8$YUBz6SUOS0#{rk0~Gn9Fz)>{3G3*+OJ#C7ZgvU8fPi*8V)D@Ib-5DDeaZ*76<3|AWnb0V!P z+<^`jx02lV)lkF*Hl+!pgtHkGnCKPH&=tM2+)s%{M+6sm>Tb{pdv0D>L{Ge~g2q|1 zPy#a5Bf)Ty?bRV>O7^i0j2vtZ6m9kEMLSdx#3@=HM{96b3XYa8SxZXKx@NhrHDbw= ztHYDZuXoFYq@Q^Vf$VU*ylPV98L)JV1F@UVRM>jNMZ9PQ^2jCrAkU7i9kZc%r44#$ zjC|dyCw?Q}0Oi?fU|l$)Xx7fv=;eHCWQ_DzeAKj&g6G_n`kZ{qi ztkF}fS9z{gD<{0Ppwi9iw(?KqCX>3sLN^iCe|@0GZ-UstIv9CY>UX?kq$CC*ED`C9 zqwg}hX&PKuTi+?OCd6L8t>|)&FL4HT7#(+gFbMU-(v6-cMGFwG=Oen`Cfh!^uiW?K z`G?}@ObcJ~qFte7Zr1q<=6u?ui3ZiThWUUw)E}JT@$$GuNp(oEUof&cl(K^)Wv2g> z5)P8dT(Qf-Co@9g>>Ju?SZvThk^#KU55kwnN?s`y{0dUHOV#ELKcV}+BoL&Ec@_W_Nu6W0j;ozHEegXF_7P_4Uj+5hBR7aW4E068T z)dPQxR-d8u8=!o%=~l~bjo>kk|DYtpH?IVqF#0YOgXO~%w^PZGIB@!p1U+Lr40Kst zeyL&GiT6_0;+6$s)AH0CvqPN(IzP=&lo8d~ZE-{`x-fgaC)tctYd@#8%<+L3x^$&}s)Cp3BnIc7dFQfd z5SH*~n@$MB&rkP$8WBEmnV`PW*r;q^wVM`kx}<1yN2f|a8;b64gA`?>Ow;yn(@=_Hd8(u}{o6bCDJrVe6~b zectEJ6wPVdgCpINp>C1qVw+>}3N%Hso$AMUumqePzx9zc<0~uYC-`2jOB4u)|s4m07c_?||jHzvM z{%T{yX0K|mLc?kmq0$+JrEJ7?(!RfGmM@Vi| zOI_oUVp?=hp2H#+3yep#gPUOo`L{ZL9dVD4So0Y3{jGJhYPE2<@AWx_#P+NsBMvHy zLqyZOMq~233=gfugYSk=;bV13zfp_X8z$ZA(s}PmFBRN1T1Z7Jya?unH}tzOCjAA1 z@=flH7g=IoH%khGxiwlYbW7hkgyfYr>DAPo ziw(V9HqoVVs^>IZz6)c-UDeO+?zELS>}M zr^RjOh3#j;Qo1+be!m`ric#rYSSKmb-H>0%IRS8NEYRr~e@H*R#fFoAtN-<)+<3v< zjP;uhH$&_CujY1b#)4h0&qR~|=rZW=pOyV_ozy>4Xf4aonYVRJcAA?A^CIwLEE4m{ z8F~4|$16ceOY>NhD0v=xmp&oa0k*42k>6o7$7m-6mj8pj_l|06eeiy69YMSCn=fIsk z@I-wC6dR1~oVIx|tj;;O^*|aQ)_cXOdb*{lsIr%`_Z~6V#Of?9P@pY3$ndT6c)^7_CZ*y#it7HTd=5rosoQsYWcIH%I z1W<0j_`GnHtD$#g48^LaPYB-|(U%HudV_$R_BJOF>967EBdfiGrvAJVUfJ;e^_#Yu zelhF$&ao6`%|fkxOSD(q8qt+ji7?ne?7eQ3!c&^f5Y<39(hV{vyUuurh5)VAXkNgM z4w-XU*JPM|+?RMugT*#Wwr5|s(=^Jx2-g{d!AF$XCRIR+)3DkcP09YRlk1wD8DSJJ z;h;?k-KNaGVzXn57V2Jhg$7yQ=XmYv7be(caxJp?DUBr-weeX}$H$T#(q%GUg}Lm7 zr_M}!vR7FyTrvpF!2wrc-8k}1rayxiPdHh!)I9XEUfgJra|^VcfS&(MQy_nqqtMM2 zWQZ3MszdTtgEWF|$Sd|=hJ24q;6lMIz3xKtT^99yRhmxr2}b;Ad@i)@s{To?A#)3(d#6Cn6TfUOAhRl)Vo z0w%0qK;bbhwGget=xMF!f>0$`UhP#bsJIS|oaWtU&g)0~*!lTa3p{h@}_)jDga_E;YJh67o7O4=AoZ1VTOK82(&0{RoN;n&bx)gOG z(7ODvmGrZ+2D59iLiZH}Ob$Hr^Us=(Yu$fthV;?>O>{QO^R^McnShDNjX#E8Ux>Qz z_E7YUYT<3?vnQV4{Zw)NQ^n1!>xUl)f0w`x=^o_?{O5Q5AF!O<7O$+gadz(ZIUFqP z>Od||yf%WsUDo}88I~^zA^h2Qm(b&*q;E?;BXTg5=YKUx{(mR*{D@$J%)pd;oLuZ$ zDys1(k9qAEwB#$vEpMQo+sE$x$#d^6SG^omM%0Ezk^t!$c8-3;PoBqn;CJ>-ipDH` z-mTw->NfMg$GZCKqX>~N%0n`QS zHc-rb9ng9eLRo2SHgC(z_~dAGQtiCMIluSUtJd1A?7R%D?+2FH79MZS*H%&nb6t4$ z`q*Muai6I4_gt-kZtsy*?*QN}!BJ1ud2Hbt?01r4Ed8Gy5(n70mBgs0+?3sO1VaPj4_A zT6SCKK5{?f8azH$Pa>G$Xa6E~86u&6+U%p4a~5k_MGIO`B*4D7qLjDmP&wpvmfaE#Hpi`aVJ4oEBs z%=KTbp<-il_$PF47BANU#^w`hN(%NvF>K+I2Lo=LXw_Z?_3txJ;(cPKg{}<=M|YT= zc{45VonY!^Vk%(X7L-G%wbpOftLIRqr##aWOp0luYdbGq_t(A!k?g7G86hb`k_L6{Ju zc;4?rCw5@&?C~~!5UwC!=u?Dzj?Ao$mE~vb4Od4>cSzS)Hyyb1JDht^eSE#hJas6G;)%WY~YM~=Q3tEd|u z@W=9c$s|GtIcuazj(Yoe4H@TJql8O&T*kip3rs?c8u-FfOHO>M(FF) zS0>Gh#BX*vG^4F4##hsC_GzU0YFMukim77kh5OnzA% z)~%;L!l_0Ek1V=q%Gtaus+1M{P5_nheoLwC&34#1T_w63_e3x29?FCEG^6q5#!nu2 zH4k@yDR~HgVUusw544M@Tk@hjTu0c31hS$V`XU`t|LlhXwhuC53@QV(7%d5&Wpxul2jwzYT(qlgK10 zANw4OY790C;h68DyK+tfee^}zUXO}^XPbn?35I^PFYA{jS6zlhF)fJ~gauD?GYetM zTq#^v5IM3T%B`vSIoZsIr`7Y4W7_CbBe5dYLU|xq)FxZr*Kfhf*7-`ljM{EO2GMM1 zQ?Afj?XrBJa-pbsp+`v3MpoDim)C7$29UvZREwi8abC5FfZ0Ed$PlW^xz*W<63qU9gXc~_zc8^CW`aQ5zO!MzP-KE+?cpG_ltlRdD z%z#MAos2ze(8>HgC*8cb+GTvx-&xn$vs?YikL(s#2eXZ>q@w80=OGt#d08hgl$i#N zMwak~r#S7dxvLv}8;t?QaqZO9lcuO(Yauy*L$jH5)shtaC{z=q5r6(MXWHsuGi|4R zQ5I1hq=7KE!&T3ILsgSk=K`bG)mfL(x&V%fd#SGo1kO$)m~0LX$-eAQn-&n4wFe5R zE)bf1st~dJ#=F7_XhKvR?coy^A9GC!t6ur`!=HG}+~_lwe*)T&q|v;y{N4I<@g64uwJV1=Y~ z*y<*}OVoW7wys7DTC`8LopS*E-?#^xx0GuuOgX{AQe%_o#hceUT(_gUg_N|@Sn5?c z;Pj7t+Dsi--~eWJiBBPsIoAL)mLZpnYtVcJR#{8YR9>mg#OQ0c3|F-sXX~VNyGmmD zhNygkh*08lwopZH73!1rBQtZA+fF~ET1MC1$6jhMNeKviuxpxFftOVWHQzpfMm<@E z*M@1TS^FjAkM|oD7G~ai<&{-t*i#6teUV~~J?x!Phcsl7pt7TRehYxq9A7UhDUMjX z*Be5FOOiX8MVVlY^$zhBRD5v_LSO7?PI|6;ayG72dD{tJGm3W1TgDvCfeD~>hS`uK zjWK8|nz%=I5Zx=()P?Mg& zD{8w?41rr0*L#_LE$kP;7vh>K0>+#4bQIK8zW5|jr0M}HI+1&9l(E`l51nrWK^n<` zz$%!Es2|{UAYG!{<7l|ak^atR`_jruPiAm)WLwUD0nQ^W5dTNPbAysS)v0zBA)$5I z468WTkz$CnQ{&BqCuD~a=2C$9R_{qo%mcOWYtt!3Bizf|OY zp|wb;g}lFQ$xH@Luc}O;9#q+q!_^z2J_HKOC&!mruxl1e>nj@L_MGthz4(keYtVdt zL>?e9WT`mNz4e56oY*5Ng84jC=hLNR)(eUwpg+eGdl03sat?^-)agkoc;JHK>o{3v znFmBk9&rL{SIkW=bjjX>8&AR>w;2|GQ>{3C%|d;CE#H+OsF!;D({Qp6CAC@t$@O?xtD<7eUS{YYn!{UQ?6cIae9m7A?UPXvwoy_!)wHoy$tWVK*XZq zv#XeRzvOl+n@BP12eFjw3x1v7$o4)n*mEtd85R>ab3I(WRkP;SMi#O+Wk2K13ya;o zSxe!$;L*_f$&&>68o?bo!qNd*;(vSeLEyQI|3k=v3isnGCTg4s+E!qX_Hhul7O+d7 zVeOUq;);`(YoVS%eRTPIr-#4D) z6=h+BEt~i?axwz3S`oxz)*AmM$w(cgy2huCLH_NIA!uRQ)X%VH?q_OZM5>Wwwj)E~5yGq_P3JORn1jxd8?VMcSw3#q4&`dpY;CSBvqHeh#D%u=UZLZQ zYnu#@d%(~;;9Muu9<~$AHpodzP+(V+P<I4iEt27g#_#wi#I;?PGYZFy)IT~AFf{2ghx?s- zfqk0}FpMG?mOT!{6X!Y>e{CLt*$=D8g0$%va&H`eAka2&Caavf7nr<7F~c`BZp#=t zofgwwrh)AbGM|<^$=a^Wv?_U(bk|m$r&@M_O03czRR?Qt4Yo9;4Tq^<88w+3Jl79r zK-Nv@#_dGW6egCz7gtmRRLgdvxJt57q|P>(<{01%jNhDkcNe$bVtzIJ*j@5EVFEi@ ze4jgZf(Y06Z8FVkt#clzu+y}URM(R8(;Pa+>T{iVlgC69wkmC+>`*DP`8ic$rLPd$ zAu#5rj<8dAV3R|Fbj-}^iMY<0)#II$VLnJ^YeqD|2h0p{0LPy^cLa&RRTAWf6UdNr zTaetQVrR)uWYcw}_&+PB^Wwy#pByQ&h`1K2T@{eM1w zIW@&I(3Q0F(9}0k2t9)d3UkCdNi>Z*Usj2(3X}wl2oE#jP%x0R(n1yY?{XC*?TFjE zNIJZSR|IObjN;8zw|cGW8v=jdkgw$P5V5!!3HA50%F?bJkbI?NdL!9unJuR_YCgU7 zS>C@P%l){~K#%?8+NgChd~*NkX0eJWBc0hDL5)rzIL^Y3qmKboj7BQ}PIXZM4U^~9 zRigGGQSZJG4p9ewJGsiymL6k!(6A?sY1QXk;ZP*Enl}=Csd=K1c@q5%kMCkKhXUSH zM)ufxoZw$UM|guW@=g%uw_DhCfUI zJNu4!T=$3vea?9VeRGZo$~26bj)6mSMdh@i<517*%Wa1Nb&xRz1b2j5CZg{kXnMg0 z<38wV|E_(s4Jx>^L5CPqS*aB0)U@-pJ0>dFlGhr&{ORl)FCBT+1wxsTYRap5bA@Y- z1F|Bm>VoBlev{g=5<#TNIQZ3_mXSjD~4fh$l)0H#_ZRXp)$N5`=GY89A=9VB# zOEmT;PeBIqSLP2~BS(Vx{W}%AW}XRBpal6=UerR`4E|4e?tg7i*X{2jZt0_7-0mT8 zi)y*IGjPh7GeYEG!70Z zry<`hYrp_*dMt5Qc0z8BNCCZRlKa2CeSoE^Fl@nCY|5=qe_P)F-3vU3Z_UoeWgwN1 zm6&0<3~XJypgwwFuPD9Wc3bArgz=FfKX?OWo#=wCUadPcUp=|aeAoa;g40g2Pq#2e zHloK0j8#aeLlVl1oPkh1eaNxC5>Kc`e1<^()xy%M_soHU@KSYH-Eze}?t@yG;w>L& zOSu@o)jU(pPGK9CG0?JB*+$-9akt2bDA~lqt;VK29#^)sO-)KVIB1s&KD#53`bs3< zM#|J)Ygq8pqW@n8v!bH0PyDxUXlu)=xqyDmp?z-40r7$C!j(K%=#)!=pY(9$XMT&C z&(U)7ie>GO?|i!Z!CgzWT&X|8Tearmu|_Zz$F71j{|}eLFoeRy3B^r zA*3tD0s(Sq5MR1h@b(#FJ$-%lD{HyNni9P$E^x+WUhK9XA z&O2P6zAfHm_+|b=KUhX9H}52B^Vhl|d5TS}Uj1-x-T4Svqw4zg>o-OZWw|xzgay7k zBBd*Fdp3gdTmd>se$ex%7T-`G({lGW{0jxt=S06P!B~E?rujb;K8Hx}Sg&t#v83Iv zifJ?R;6Lv^pY~#Y^9cS!OY-Hz=?2HRBXqfM?+GmQMC^kN{<=53f85M2q)daDWbVb| zu3Fy{@{-k(Wv!Dgl+{0d`LJB-U`4?*+j#z7L6^<3V+;6(4~+=3IFu|tfWNi=ORrK( z&y5(eu+4=_A3IXX*RLPF)-qEfV0`ge&+9v4hJs!KT61=HhXo(m@f(zt{r&KsJKzW=0=O z{SI`}8l#KHraE2aNV;(K;qiwf^rzla|KhAorF07+bjgOL(z$ zy$i(aJ4r^<+p}b{Xu1*U^m#Dg$NbUnV-Lrg1fYE|`#pRPIgrBLB#|_N(o1S6(5dO3 zWa*Oh>xMegHCes#6=f^6m*+3?dm zXs@sOx1b5ew6h}I*YA&>^m7$=_!URxV`U!n@<%^8rsaI*TFX@NE_myROyhtTEmx%G zp9B8?<>e3Qzhn8cNVrYgJb|*fw#cxIW$RH(++T247s;TW6f^ui#g0DxCV0rd3O?MEBsBx~b#b~PRc9*nV7OlJGUqOYpTat|lO8+4kdy(wj!n5WVlA_?=@?f7DMj zB=_WAtU2&t_|tmWt>C)Gna15EVW&W_5gPanPVk*=3BTzwv7rm2qSSm&t_bT`#^T|G z+XdZ4s9@W=Fx1A*bP#7_f^>IG>2WjOEK|?GDJ({UHtik@eXy4ns&K2-x^6t!g?l@2 z9|VL~ui6ybpE@LWs^XA>+~Mm|mtJUHO1yoM|F43BU;Y(40jq~=;A3ADq8l^eoT52^ zZ?-xDC!((ngi&FM?AxFkM$V*xSVeK={6gU1sv(^>mTebKojK62UtQEm!-)c>$P?xs zz4jR|9(eA(NeTsDbq09rpLKX% zEeXSL4g1ijURZsVX%-f|?2|cTuCD))6Gwbn9YJjL`PeEsH`DI;cMOx&ig2c<$FOhA z>4_2`bCw5DiyeFXWFWKMRcSC_b=F9c) zQD{-l0M?97C{wj|fF-VyYJU9q+rNJ@6HGdu2I?5aRBk%`CKCsY&%!3dTt;+nvTV>H z0EE8K+XXq!J+#_fv3$50_A1b9J?!3?k9WQC6PEz^1mEe3_utw*G;;Oohp*B*EPUg$ zsJvF17OFx1J2Uu+#GgFVt+9auNXJREb;Bz#3pPsaVprBEGxF$I7S^UKZ1P%ISSX;91ny=XSlbehI0t}SBtBcbf%nKmP6~I6-Y$U zx08qqVQ*CiGJC9OITAKDDOrCXTIY@aOgwXWX0!RYtx4s@rc};!zz*1|w|8C_0g7ZE zpl}<;G_K*4gWS63#QMFD3OIiDy>zPZbE1b&EcVpw2-dSY2BVW<@4{z6Pk&BwLWGsW z&bAAUGjXM^i1YRap9ZN5Z=ChA@n7C=rCNF%@4#%T6$@|3Ol*wcTlGQEfPbOHlLCCL zIn;6(3yURVK+mm>C5Yo}ASQq&#fwQ`CMjuhh8YFOAq%{SXWI^NzhL;I+d;P5%xMJI zfoc4z0tq&&n@-&yRu)_Mq!4>5jg)5XrQb#i&zJ1qnAa4-~76=zM(t?EmRbLAAMwRteGo%0&f|`;Rk5CyeCWIB)L|f# z>S)GNUBY!)1!fhRn}x zHwWpT0%xp_m@g7iwRHOyYU>?ZPA0K4o^oEv}ulq^Nhjjb$x$2kLdf{~^ z5cnr?t&LH=9+Hp9xl~V=NQ>i5*x{R8y-TN*=A%Ubn|DfG6DQqhE@mB?4ieW|;-?=J zw5c&#M_u}nN{tzW-S4^9i4s}){ZVjj;tRX1YWsW&!+OsicUZA1t|&9XG}*kl(M!Q7 z7hxc`gG6wzvLq$B1EIury>oM$Yj3GDU+?rvitjqzsuYF|W5K)8OYB*;IYYBs2hv#` z3FZ4;dG?EOSF2<%$$@O#=@Y{}%NTErCdg1LA)Ttro1r*zs5`!O;bk5TQ?^o3LUWIc zlpagTwda2sUT9)T`Tne~^!S|&b9_<4SA4O!d$B-(pzq0f7Z`mbBo|H8e8e}uIa9Yl zb~xHbyaInH8$_fOPt0tsq=OsHXE1Vq8o?MBY@6J{KXZ2EBrbJphV!_zSc6n&K_a?% zCk1UOLl!Am*0xNTa8lqNE;stMFW7Op{gY?r?KMJJHQ~@-A3*qR$WNZl&u?7yNR$KL zov}mU2JYU1sfxtvCeOe8{@=g;JVaP>dlSO>ksR0C%=)Msm-J%~$7S~!&P|8UN*MOC zSwla0Fpu*X8*OyHD|6g%@ZA$ttx$U~)Uk&jz?_~j4qRiU3H;+3$x{78hfz}PvoDU( zdtMxqIxM-?;{4*wF{uwyTixh0H#wWW`M8(tE_RDtV)J6po9@DeWw)_!zAwJlW}W z&;QyTTnB;3XmidxU2%rwoPJ|I5Jux&=MARscXosOB+;0&Z2e*Awh5gV zlwl9UgE9m&D5X^FkvNVK*~Mby)2b~4#FU)&>C$|y7_703AjRf8eoB=YW(!HsDYVd*cYpy303rP;pJRw&@iem{Oj3j#}y+chC4$KKpC@Sj)wF%NcP3qU7>bkwW zMdF?FU42fAehQS%NGY50x*lJ@x1w#T%YgCT9Cl8tws`f-wA{qdku2_@9Ia<;F{lLMuOv= z9c_lA(SMtcxrXg)nNwlOZcB1*NC6X75$sX@PEI672asa=bKdO`V`t8$IAKpa0+!uS z#d7Mpj-G=x%e(GKK~NY{x~10U%#!5bAA@bMPeBd7HfrQrmvBfWE1U!|q36e`ww;(e zA-dsLr)bDf8g{p9B)J#rrr@y6dvC}F!ytQzAA;Tks^36m|gT(Yti_ujP z`mAa!rBDgCPk;(ol^-`Smy=Oi+pMPKWFI-+0smlPB8#Z{$>Rsk>*njjF}2tJoh-!j z?o3#>t1`VB#H|z00i>=B;gz>bp9T3t(GH=ctlG$gw?)v_kPC>%ZTCd&Rm>YEoL z{D0iOc-Ht*;<4|x@z8&zPMz`d5dlnRy6s($d|>GR&YKXZB(~WF!oi+Qr~z!Va4PFU zNkw&Fi{9x)vFyPVj}TprMxB=$oA4uDHJys(Qf1?Q{i#E#TSY0UIC&rUFer2Thu5D~ z)rj&<#Hu&*+tP~BzxB<6gJBo$hcK9oUh|~mxCJ`lfwROom3;;b^rn99A$}yT&O

    zx5ubA{qJ%_UD)Xj@2D64*?j*7vZ4P8$kzNXKsLm!+hPueqNZv!XOz0h8O_71`Z$GkAG;<2 zlMlsZB#R`AV$fB@QbUW-CD-~HjWmx4kQ!pyNj%ra2hLNTfz$uv=u3>AOe!juf$Ox4 zh6=BD(pNh&ATQb^SMv^4pkUPQ=$Cj7)-0lZU%VUl(jvRUD_K8nAjDU<^=}}Xk+rvK zhbz2QM%JWZ9zUZBt)Jdsy7S7U#j6Ov%1|h$Fzdq9!*`z2lcqovqUP^-Yz(a7YH=}O z2@>MOS+`M^%uhhr(FkgJQUvb2z5-?j%g@(Y9Si2+kh+?TAy6k34fHuT=}A0&ly+K>W0kV>jTs`gp*aj{b$5OuK z4!~(DQ|Ck|+krUJ-;r*P5%HfRWV@e%}Hr_znV*$6)AZ-Cem zPMoWNirPOG&;>NnQ|8vkh{tphgt$OqmQ`Ya zlo_ZrN)B50&KfA+Y0XUdly8-omX+L6SC3hz><2W|z>e=ZumvLKqS@yK+x6*=*l*ulYXTeN2<4U9<4;ZhVS<#?E=5*lw{rD8dw7)tyZ;H}lT!*2gfUiK!2DGIfX9Uw|+-dN# zhCDIb{5qi$jXgm09GYZVGlC=9&V6O;5Nbbs7;X~+xKkYzp(bFLIwZCtCJhzeOFom0 zsDO{aCv>J0=J7eL%s}HQa=p}Ap$&Q4B5UpYJbM`VVe;0_Xnyc*eS6xBs{L@K3TI}a zmCf<-pH%>77G6`ZuQ=ubP8~+wQ&O_+26qrrcX8x%Y`#kewk1oN+3aMZkkX9 zL7Mf=?q>Jz)~gx#oapjpeVN)(yqN>be#Gcw@|Cdwz2iX+INKfvE+%UeBueOx1BuIBfM$(vxD)LPczA;H^Imb_PgX7&Uy)(0E(u75Y+Na#T^}QX3-fZdC=OuHMo6 zx2PHWQ8YKSZ@8l)p3F?l$H{}VkMJry2CL~4n!jo57q@3?O$^?iVoVJVbN?)V`St%Y z&i-2+;a@*GAZj{8L{s`~AZG9t7&~xkV>pb1UdsQW6Td6K(j~^cJE7K_b?XK%lo_D;UvUnVC(sxL! z$2TSE-fr)Y^4t8kym*X`&Qom87j*+h$ z=k8wId3Ur=(0Wa^`(l)=qnqj#V)~WEr?DTztD0`PJnJ9iyZT)6_pDhDks)-bN7c;; z()K&BPG)fBRrS^BHNm6d`6pYWmFk~04e}nU5(M?v)$Idg|I^vxzn^TP+gV=VeqRyh z3z2C`038cOlb-r~-F!bZ(eB^^iwoMli=?q)<6p2DkA9JSjBVG4eBZ_##C{zv`^mE+ zOFQwFtup@uR{-dNgb&S^kTnSZPo6TiBj>rj?7sfLoof82AN_A5+#dL03=V(Uqui?$ zOoycK6FMx0AeRqljGBRWv`CN*-F&9743Q&4pPzX}P=OaNQ~1Xf@raW!K3Hc(|B=D` z;F7N^UtHmFdhtQbt$ya49o1fQH#z?v3kz6_m&vvMGzUL(eRpJXL-RCrWT9J5N43tG zh*S?6A5R{4a@okqPDD5X?JRT5VA~PSpIG;y18^)40nP$<9h-+@+~`kg-T_k1Ko}iH zo#_}ljB+y^+uale@;lO+H*zZx(BkO&5G1neyjXTMbNu6xNAb|^N5Q7qCq}DXz3Z>t zw_3FD3Y4|B_PP<@WNm6maA{fg^&fjtZ0=`TFg5R`d?Vf(+G(MyiW!S1n48>T>}l)h)qKQg?CRS@*d+ zx^d2-ZcL3e=b`@m*EDU9W*bB{R8Te=m8Dt#>gAaHC^(vhw22y-7%jJ|JM1*JT4moI zXWE6pRQ+DgW>`!WWd^|mTXx2^e)O(g21Rrxrvgb(V&Hnjh~R{Ew)%OqN20zI%J>0& zBb_QKNMRcRuR$w9a95~c=ybvkG!R#@9rL~vtMc@r%Z-5d zsIZY&l{$lGlT+T7@82q&U~K?wYGLHl&mH(_ITn zJ5*noH}zb8l~%r;|&a4!g*ZOEdoHqn8Wiei%Y4!9588H%BWG07#->919i`LK8e3CxuH3Ypsq@bBRyDPcOr0iawtAl?eqxRu^5ap!RY-x!VPDg5Esq%+JqDbf?}^w#Pa zUE_*nzdnzGC35SZ457g`VWWo80M?(#ha*&T%ll0qvR~f68n8rt6lKRaQJ&tIt!#>v zQGQTdj+ky}+{|-s@V1jrb+;QW{wuxCW+B;|gt1>(F67Ro0+Fo8m@ixzV17<=vX=_$ z9-4&AuJ5h=ph6BzvAuvk2F-DHlpVrAbWy|`CN|JY^p=k*bEl6oM?39@Z#pA%x)%z| z1`6<>p`mw4R!*7wQRm}5dse%$b$aZ!% zUAKrUr(SQL5lA#|U3G;yaNCJ^OcTo*b%=Hfqcf^2UWB#-JNr{xv_ogXtgO?;)fVhqq5<1{_lt~dRiS!e8jDqUG9Xq!e~<z(RFCIIi)*a-F%}JbB;Mf>X)8gc;WtCF!1f$3E2t z8~~Ya+|uF|(#%<+CwTdET{p`^8SGEo9lcAh`hE5q9)v`~K*~W?4swQBIguBDx@;8X zd-$)a1qqQ5x#lvwNzt2Y!-=(0A$fy^yT-l(-W$?a zLt!72reHlV(eHpe<5t&9&6DCn_!clTtC4>TG*A!m#s>^(eoRJT*B!`nOZy2E&0w<4 zb7pd6=| zE!zr-a)3fNjl(7Sf`at#a)@Y9r95&D$Gk{FyRi%=xkDMnosc+T*op59mFHaXC9dKy z+lQ{~;?SETNJ8IG%(*lknBZi>7|(N^`U)VruV*@GSKv=uD6A{5EPR@v&J-VhZzh;; zHYNXtlNY~0quPJ*a$RwVpjhn{=GBeo>(o}SH5IRYbMHqPs$bI>g|=)5P5OL)yI%<& zPCf=-JFL+sg6JW6!H~KM*kZ->54xa6XRGQEh0{<(A85koj5mX3QA}l-NlCwZX+fLV zhv+VH=$&Hn5c2r>`QlE!5N^l04hw>IYoYu%yxpjC3Lu@f>eM~mwu%i7v??1eTJP6E ze;EcTu&EnN=;}!#L@W90gLuygXti8f`&@m4Ehtf9xxuJr?b`NTKPFPDBXt7D5b-oqWHLN zG`?D9)6dA~Tl{ZtaO#Z!K6u{V%T!1fg1A;N_Lypp)*aMn@e8&mChrbQoTNggoR}$q zBkK-kka!C84LWg>+SK91dRV+PfGr1ZGQ*pRc*Y`_>6l*jqrin7p3HS)q`_X$KgZ^{ zonyPFjXF)5g;g%5eQwE5ba9W&wN40q1E;~mM7B%q>mu(KmyPh(SC+xDGcVhfigw&g zl`Cy?xmxCuJlE(GbNVh*8)BDp(KLA(RL68PFRt%el}4;b$w+ zra?ul8!j8Q(`sWxzc#9d45d&;9y~_0Z1STI1@-!DJg7v7t39 zdN6GxnqGH%41}E|5Jhmz$MmF5mmW|7{C3z>XP=~%0>gla!u14->h%4lx;^EzHKZ!?kBDCeeLjq5K5H|g&Ot9 zp{seOKY8YBHYJY}{?>K>ZV2-4lsLyJsK-XYgxmOmnO_)3^GiYaj8dT&g*RokH)iM7 zxsvVzRNXHOS7OOGRA$HiN<^{e{$R=puV<7}9Jm*K{FzFfnq<>#`{MQA zrmIB_jnmA6vPYMZ{c+WzGFC>u@WyKje(J-;N;V|hHY*nFj1#uq0ODmC2M$Y%>-=UqH#UK=R*df8-B)yvmrqH{p<6SRu63~}fmr$?{`x)V%JWqX&fC~YEs7l7YnH5)l z;Kr;Z@8oUp>S-viT;7-I$qb{p*!R08FLv%L;adkPTX&~l)|#9QFFJ;}HoH8MCXae+ zHu~q-NHQB3WR{yKRn{48D{X zAJB^Q-gPbgi>sjUI<$shSm~-W_^5%2mAQa_FIQ;1?F#VQio#U&$<<(JJC6j->{#FZS>Uh&_)5Hf1Y49e4e2e?ZFH@V+<&)vlw_IEYCkT1^ zqpNbZ^GNH|Lh*CX{cA1tyWyDa9SHLWus-KASq|1iXESirZ_tYr6?z1q1-AkcJHjoE zA5{UXofz>pmP;z0nXUVEbQh6-wEqL4B}v{u+-?}42RwrDpRge+zS-<=`y<8aM>V8} zu~aU5!tV_-5aHtDH9}q`VhMk7DzKg~3AE4$&L5-gUzP-9d-=%GRF8HraCF+kvZ?h3 z%CaXks4=kIBu~U=Eg`WYd6^0N#|gOg_Z=-=X(`@E?&*ox?f0txSff#!_&a$#PR}RZa8_Tk0qXAyJEKPE)k#4XzdkE## z`wQJ;{m9XpkU1im56a+;zRWlrtbdUoNb1zckc{}AMw|H+Kc@C!x6)AgiP>t!ZLP+} z<>IK$j!3cb+?cX*e}B`+CeM#o7*xS14fa% zjjhX)_1N`7MlTfus)lSSJbkF07zx8e)`bgKnv>#`F^VV}d2yE5ej2RQbk8Ow;yK2! z+Ohf?S_8}dyN2u85k>sng0T(p+~lygkNBqzPbtYKciDPZ(09c1*Qj22cUezE*;Da<R+w3(iNIUGj?5Kf5ws}1ME1~~N&2rj(Y)0dc-M`3H6aTPu_JH;=Mja@pJF~>t*Ua1@DT|r;?;I$0s*^oSa5)t7TUYPlx7k-Qtt)d77-4mddVfNiP1d zovzGet%HWr9#tol@|EkBhi@7LEr`0AT)B1E{j>Lp?1}@fT9^1=9JwU@*w`px+)>n2 zRW-`UNW|S;+qyvD#OoJY+5NF>tZa8N@K9Xe&u@~E-lmDZ(LKZ~!lSZghkbe4Qc zpKO!j0lohO4@K|*6Q;zEIrRXvQ zru*_yZk^2Z;LxCK@h&DAlUw2nmcOTE7r~pKWQT=?1jU{(Rvz>GRG(!NZ~NP#_R!sq z6Qq=|jkSt`si21M7GB3SGLa=c3J!95$x{QX0J*ncvTlzpXa?T%K-d~s3@+JIeGnL$ z)o7t_Q(cn49Og1tX4rMEvzhcf@c6FTEfpcOCaJz<{kN%Zop4HN!L+CE(x!Uxt1Bek z%;WXG%oc5L&B_;VufbWKpH|jpOU{Kmbdn}~y@E&%Hx>C^TPuc6_6uo|^0nm30%aty z)7nqJH#uhoV0HvKLL?=l%IR$F?yV*x=HAG<$7AMj{qB-G5XPJ&d1G#ZkU_b*p-G3i z-VWkf^kZB%C}3E2YyM3^L#irR9$7MWWk{5l-JT`J>R%nNs87)0t*OtnO0hiOd4D`$ z^_L#R8zY&QrrD;Hj87rcqBA_5-6p$vw0)n*6SU|`CO79s9LO_i47LqGc zq{&DfX^|RQh(G|TkuD%0gd#O02uM$)1ycAw-rc>sd$--)J$rWlKRgFRLdf&JdGmbR zr+k*%GuL|(Gl1I*=wj(Gr`2Punm|b8H?&$Tz2DCb036`?v45Ijo|!yp=)`_P(Z}65 zA>lJ=3tOTtLzjOp+Khjw^!m}0&Qpgi&ZidX;ZT3S zf6aIq@a{>TeDNGx$w`ra>CzFbla^^C8~Y@`PMh~OO*^^58#8<^w$2N}AY(+ZpIV_j z{)%3n#SnD_kW;@y4&x~xmkZC{Sc0vQYY?1b7!AV#eU!{d1V_jf$0201Wg!6R1N#<$ z<-GlO2~-cKclqYpdB$MAm2_YjwDWp+^Vo0S+j?w9IWJ5e%P=g#eyfaKO2cx10%pfN z2&eCNHX+;82`JCvuNK(HjgJL@BFMHjjAsRL0OL4KcJ3};XERT9wW)XK6u8}Z6>t_h zM`2~|yL@ZlwPo?Ud|i7MKV#>xUgT{n>|b%l^frxPJT&$Tm_2U)78EGRSzSrq=7 zA;5 zkbia-pZ&9wsQAxLqSU{35;KT+>gabCReE%otJ3xUf6k&Ryd66I%J$)lm(|S*zu)p- z3n}O^nW>r^;S0Ymk8WvX%gD9Ckuox02Zx_zAlyB2oMO;^EGi8(!lrQm zN=7%84m&0u7Xv7|l%@ zda;;GfcZ}0DA%BxjRh9_7DR0>)!|wjWEf*Wf+!^;IeVdI5Fe_gkdl`_Y97@q8-HPF zb4wI{Wclpr9)gB}$J3m=nE;RrB`NnA=61^p`?`|;$hAx|QaF(sX@suaG93%FA93gd zB1GBGnOAs+_!-GGZdEhE={95dB?k0T+hGD;(3b(ksJgSr%wKX@;#0j5T6#1p|GbXo z@G=@+;;d2et(U;U8NW0>%EGi;Foo;WD+_#eGH~~-R?b}XmhAzGEZ4KMvXxysi_LPT zisMG1*6OnTTh1m#;m&>!BL%mjz_(92jdtoC3e~XQ)9bKj4QhVAfIGb!i94z#o9k+m zNNgNgHxz7>)Vf(Jc?2LA*DNaBjJ9aA@qSPTwkcCBl!Wvm=(XM#IF5IYCCrc7ch7B- zN0$ih>9U8s=FZ0#_?~j@{*a!i*QaZ=pkY6{FrSo{D}M_b*3pGmvnp9uM7TPP<;^S$ zzqp@qM!6sM^`S_6W`!i0X*gP4F^LL-K^AwmAu+Q+)DfHbNS#9zjp){?NSeN+ ze%J(`WSOq|qRArhP^VCzkwT7iLO&_4rp$SEmyfoLC|%|5$NYq)?J2}Ecdp5dG1bZR zdvzc_yh)>iCW~q_PjZkg39Ry*=m&VmG{E)($&RxpAN#J%!=UnlJ+T~>VJ+j$SKpgc zm@e{3ogX>2EPtB4Wm`WhzRh9pFb9^U7c@oC?d&mx-z|?5FsrUj!YYpnN&O(*`+L;d zZ__6|;8kGjIs%|MUGC(UXAa<=#vXq-f|0tCq;{p#-A_xQC}{|9I84xQO92G7Oi|h5 z)H0jJ2it>$*y&?$1j}GkILJ4D@(-{j=Rxd-5Od$JJkf8Q-hMP#cYJCSWE1jYmv0br zf%jffhzt1_Y^{GyS?%ARDE_ap%2>64d&Y>O1H#Scu4#OeacIp2%sJ*(jEcnmuI7{r zqj||$?O0F8Y2zaAY6&O#20Oii2f}-XC=r z$L#0B33|yw*UR1U_IR-fwGMUtcWM&b2-WlioOh<`SXnJ~!4$)JZ0#J@ zHv^#JDVwjkZ^(}kdw4?-60|7_GC~EE$R8Tc_)!`W2XurDr(*=#d1}KPbEcBgW3LmKs<|@v#^|^uo(O!=}<;`!Ld&UeIxG566h1EkE67P@|W$ ze3>Yln*Pi|Qu-71b?QmZufPGDbgeBj%V9w*FtuLFq`cbsK{e7X#dKfiEe*KXOialI4u0x<+zx}7 z=!DX0y&ElIb+_P}nU7JZvyymS?*1%N!}7|yy_;84os4>`p0~;6AQek8cClgwatcW2 z=rf&`m)T;RC!f4d5p~3X(1qx-cosk$yCH5@ChHDxur#vZJnv*x)a~l}D64_CT;B(t z;@x>x6U`5$)}T36db%FzR(b~_awZDR3Uu$pWE38?8(pfhCBs89Wo;6Mn}t=CNHrE~ zzTa%T>w6C}$xFAUiP6-PF$7S4L{oj)f??r|x_=$>)Gd2`DbKEwaRQe6Sj>T-& zlgPJDd!^;RnC(|JR~5yS#t>bRPHx-8Z>2!&T1ymk?j*R`WTzm=<{8#Awl)h!Ba{&D z(O`UNM{fQ!tCU7O?x$%9%xqJ;RTfg_{#3`04`oI$Eu)rHqP*;37QvHL6bLjLai@hK|dD*uzD)WT-!i~>0E@~tv(^Ng-+DNkM zC}N_D9+b#f+ze#S1%r(0jgC5tEEwJ|_*{tBP8Q%DW+7UPi;*WL?EJDDdFnvoEd89l zh-Ne4x)MoWNf}1MQ|J`D&&B4a6vcKs3W0xW+BkKKY+Yb+x4i#yuqC;S^oLZ@j3 zeSU?1*Z_&Z1ha94>&CBTKdj(Iz0y;V+d6i5{kELBr3W@w%FEqNLXut%+Y~skS4vhl zF$>&qj3|puBR4~i*`eVqS%v@*T~LcgyB7Hc57Uz0D;+SVc=aCfv+b-RF?y1x-2!hr z_G>+u4ivwg8)Y&~in6u8M2N|)Cq3>nSnh}_IFu;WVNv1SCa;m0KAwy9Z`FPvnj1e% zGY5Owu}B+700p`v5|cl!SId99#*M#TUQ*a30v805;uM7mgx34wy6@M?Rs>*fKp3V}Abn#OwdpuW zc0}>}iQ9b&|I-XBmMPJo;s-J9Yf!{C9idAc`Zm->%ZMx=vvZE23jj&UmYRz8C{+P< zl?gTD`aaqf7qy|Jr8`M`1Yc|}9>3PQ##Rr!hBq`+Wp@M>$#zz|`8xF*7-Y4W;g`56 zQFe9xvr#4$4FHFKvew5502mo}AtPJUYON@6f)3XOvQ=%Yy4Xg%9v-X@XlUo6yd@M3 zBDtt_pfE6v5`-5ls?}iPh4ZrCEVyB{EQdeYOm<}1+5l{X5S=^2(*%HV86=qjS2X?%5~uS- zCnu(f-~m4e(C%LLBy?wuqJL&S1U|7GU#4YqKy1X49o!W)-F@BonDY&bSG=B~;mSU$ zzDOFSX8h7qzg@oK0ps}B`6KpCT6Lr^@%7`v>4cj8&6_nQR#-<-e`|!Tr{<)=rtJa| zRkv+vz)b{3ndQ@vB^1$b508I@k-Q0G-DAj3w})!oW1gGSV-7c^qv&c8ZtGkPUjLjq zkHYxkQ?)~Uj@BZ2>}$v@a%qrZ?#CA*hZ*z1iUI|cJgdk{xsj%A11$ptgS){`^9$Nm zHi0w|Svp%--2Q7cH*LJ&-KQAULlGT#Nv9_@C;{ChX>wy#)mFb()KAIbrr%>7pSH^O_)} z^zbD|235ZgK*9YGo2lFk>|+E3Gk_4_T%j8V!pV%PNLni0GP=SI)~qp9{bq9Es*RV< zMMn6Gj!2~J1Rjy<>SpN08Mm|9=o0;fUU==AK`2^F&giaj%GD4dq^4Sz-1>wI5r5U8 z4PO>)v6---@yhTkcP@93;KhcSF7<{sXmIOvRMFOqPryc2v>8#h^&WbZg=zt%-w7{! zY`cRnt6&-zC3$|3H2b!nL_O%hGHmFkK@K~sUGP>+2eTj^K|JWC+#gp|$*Q+$@}|i$ z)|SOz>eI4Mn}(|6i;^$f^#`4(v89^1@>`@Os|c%0Z^yfsqy~w$b|wcdRwTv6f~-9R z_5c!1F82*Zn=+)p6e`#a(+#T#8VswZhq7dWI%Eo)b~RC)g>o1qR=@-WV{AmDyegS7 zvjtNvWLr)0QeZX3;_cf?3Tg4paVVnFs?d8ztXBdd=nZkz)#+n**cik|Cz!-pZY4Zk zU8z6!TYe{h>m9tQWrtcPsn#`JvtGs4buM!Q*9skp+Kgu1E9SLPN#XCY;kbi!*31W+ zz6{X_kUrS5jx$)JzDo)s?YNr7w5n?)uOtuu-Y_d`~-tz6ftc7`g&&7KATe{1tqTar0 zc?EJg>C2w!g=>k*E_WmG>XqArlUqpFtPKy09-QsKkp+z{re+&eL<`Ck=kd=2zH}qw zWi>Ar(0Z-<&=00o!!ndu*jxvsj=@*#@d~K01MV~^7hFvY3-YRIM|6jpR=_9fW*O;S zf>JT9@Gf4=BkXdC7@RdQ?x^04XZ`}jQcB_sxsz)}VlPchG7lASPMF+9`lJu8qrAIw z*`%jBm%+y(5bg7ccNEi5cm0l4VbWyUACQOG8hMb|_n3om^p# zAj_$k@CBu(5`QMK|1kGmd+!UPe3!2@y9vAV`~1dmFz*6+u@%d`as}}1egsVTgk8S% zcPUSI`HB#4K+%5-KCx4#kNjb`|9@gI^lum0|CJhj4;?Z#x;7PxZ-O1hjS4lBPsp;o zFy~no7OYgp`-RP#)%V6HMq3NUS+3LjhN@__`5Z%9I`qbX6z{`3=F!-D#RBr)AI=VX zjd(?M4M!0VEC=P(N58=@eW_1}tJ)}cn#Cp8o*$|sv~g-Qa~!Q3Z+RAYtU&`b8`nWI z&NX*%Yq*s4j6rFkO6Xk1G?B$I2RPC|hq*zUqXuk+V9#;KRbVGaSU(CNgwR)6i8Nev z3M!%w!MM^i`bEql`5qH>w+d(pv@sv0AFk90Bit)cEeXx1+Uw+^+#GUm_v52-EpqPZ z<`kJfk4l|MlaM`S9#=P^GP~_tZu9M{$E_YSr-K~>ks;DJ<s^ z$P~Mh%ZVE!wUw@h?W07eYevdSgR^cq>odNI%SsfuV@WE+fY)(#3j)!Ba(?4hR*WHm zz>d}p8S4Aqk))v={(G*1&l>g&D~q-`s8>`0X8@&HRx9(w*qvdMN4HWChgjGq7wJIX zpX*rROGuNZ)&+8qJrLrVC;AAI%khqR{RuJhf!`9H%D3c8J{e=JH5+PdCbDd_N7FWWqLhL|(Gg*RR<9vD^UA?#q!XDtTZ!2OTZnjAe)}D;Rgms zWEI!+Yvo$ehFfJ{iN20=rwY_5Q3;95Wj2*NGIQIC4dG4XGU(rNgsc9JBMd?cFh7Tg zsdkGuQ;)%%HOb+ls7UYCqnvZBpsb47_$k3K$pifa6?yM^)22xQ(VZAlO*$ccvVcxJ zL0!b0tB<)~Qw4XZGZgDFd%FI$GhMFpPIeDH-MY(qAoYp7frW+P=p_UB_T>jgIVYV= zOikhqOlJ)9TM(9DaNB*D@EZFz>9hF9GEgtLp1Rj1uDvQIrY~pN_M2Oxmk4*Yz@{l z&3CDqhI$4&$`NHk=*Ceh+K~6yGMy^bh6+y_`3H{HCpRx`Ju_B1eJn6ARSsa_#%PaT zXFF$HFh1&6BLO#L9(bvwC6#*%uTxZ*+hVHgO*1{NKuJ3*GWWv9)9A^(X;fu={+H=) zN!uH*>xF}}@}>>1%Xf^JO!mQ-b(k?kBvKY{aUau&J*5SIgSHt0V1BleRFkRSmG?}J zSG+|q%njAN^snw zoO2UDGZW(TN{@6HU^<80H$9@~*E~!jErT<=#N4jIyLC5T>G~v>>wC0k?DC0Tc8{~8 zpmZ1PySi2YN4WcM;Rp-T<2S*GEB+;m3!K&Q^l)BY&7hk^!z%Z@>^8O?^38@B&P_bM z#VcmYMwmmC|Gq^Z1bW+h!37xK&Ef}`8Qr2?zI@yZ1t$hMc@`5twZ%!B1nuy*96eqU z(1!TI3ip+D=g$%MZ>CB7<1FCsBK53;%r4)nwWeLZO=Ul@Vj~^#l2O=7;x6AJ52Sjx zTh0u^VvTwAX1jd-^AbOO)d?;;y{~tt5`cHexn|hSue>*=-}Pb61;uhh>I`@J3Uo@1 zC3tHv#vQO#p6mpZM1E`}o|pD|((>%v|K4K%a*zjb9DT5AOfRo37M!Pr8~9-d0ah7E zDuh8&@$sW8M}XI03RX-K~-%%>8_JKu}THX^_xqt3)`EL&y3VK{1 zeD>w`e)Tgyyx&vt9iQ>zZ<4o9&!;&tHo%m6;Li*qqi-ub#$o6iPJUf2xo(fZSC|4+ zd3BYqX-BX#s;id${$j)PZ(0BOU)q=R!_NnQ);cCwI=2mG)17}3y8l~DQSe3GzF=*^ z{Ka-wpYIOm{h@+u3OPH!^K*m9y(j-H)5e!+_JHp&`1;NL{rcW#@3q724*gjh>iy3z zihBw(sZTZ!?a}EA9dAw=RkzDHu;<6v#T_2`;&;Z;H;Mmvi1x$JkXG4cD42jtFxk8= z<5oegp?Be^W)OAfSL1KHd@o^NDy9Y53RhOS)^y_&g*tYBpMA2Wc>DkYAe+h%;TR698jk%)NG{uH?pV|Gky|Wh^ELW5t8L zgp1?GNDA%p4TKw))QK`3cljK^s^?$-G0YO>qCuvR+d>KF+Heo>f)yNA2jk$k1$PJj zPk*it4JRk1c&86#=G)tT{%kd7><@59T0TQbK1ro2TWXe;S1vcBP^d#%<-Lj*+;7H6 zM<3U}tN677bu;;n4nGU*tNY}+fAB7H?hWW1_w#JAX-%j~NqU~mQDv5Z@GSB*;~=Y| za8W~bw#;jFzhA5+V>3Ow!|%7!>YyLR3BTC3Ro;acu=LnAt%nmwO!qjX%UI}JpI^9T zaMY~dXDcpQ&6VA-*l&pJ4sky@r?!`R>$J*%lXsBx`fy&#x(8eP3#>}*eeLRtl=fyN z$zl4|iwf=@x-hkA*~yeK{GJ$REK1Mz>FL|t%k#lF>l9FSS_hzTY zYW{Pfv?q0uKB*J^U_m=G719;X%5{ta2cyv<*2gyT!+y!J@SSX%Jyf^69dsU zw_GPiP??EL_$C+NKAr9`3Ah#s&1s)kPK+Ho4|0-~0vVZ`Ho{L8$&tpz>vbWg=O_7V z7=tTue+mX{Q~Xt&+^qbV%KX%#`Ij$VsRfMou|8AZuTu-2_`GhtVTZd0byD6k+ECx6 z*`f3&#e_9>Y@XH)V5J8@!^j}!^VSUMQZOb;hc=b6hRv8)>*tV3HK_21Z=>$QyFNd8 z0Dt$$)j#Xz+l%7cPi9`WDOy7%l&JfRJPMYwMdhnKkxScuLP@!;*Q;tM$;a+>f|}m`O4p=K)jbJx;)lz`F=M?_no4 zju^ukh9GH-CV#0vjo}LOs z)Gptlb(lD@+0cou7EB_(K+zJJSuCkLOyzhaJ&zH!VB*|Czn5w3l@jqO)gsbf)%zFJ z<`s18W0@=R=A#+n$1Rk-z77`bQ+9B^Zen0TR+=8_+2P^$mfKaH0^41|G~?ArUIBOr$ri;BZ;JPFtG*qfy00pnRh53VhuJ#7)XJp+yz-y zz(WT-;0?Sn1XWgfFui~LbArX6KokQca)x?1=K?kyWGWgg@InVte7_?d7OcoS`-z~J zRCr*>8QVLGWu3Xf6M=#JX-5JLg3a@8O&}c9w{Zc%-2*~Lqxqgi71-P|jB^x34FL#k zmydh2K@>bNo4(7}{&gn_%6nD>7FGCcBL%XyiQ^prnPX@y1E}7GBLu($Yeu_#)9XQS z@SL9q!K%!E-su+HW*hJF?RkN1YG+}A05}oE4u(G-;5Bq|!F%=w0P9%_Z-O3$bGTp^ zeg-TS|N8tvOj^NtQpIwF@96w3rw>G*1K-%q|8Oj__HLdif7HH-;y%04i5n8F^)1R} z&00b~#mQ&Ax?H9w{kY^M-c|9(%SSvrFGr_6Omh?&h_^rz#E=UqLEWZ?=hG?rd6nRY zjhh2u{_U-}D6C+^0Y4#YRy<(QUG#Hp(l}inxv;%V^cJYCT^OSV!La*s=*|M=)MQ*jyakXx>G9^jpO`^}u z$UY?J#96x4$H6gk(Ja$V3KxeqpE8cb9)q-u&V{I~23y=+KnRlrUpVkHvCrx}r($## z+6?vd>j%+-bZxQbmi|#zaK9|-s2y_0dr4!XN&i7^eK+UI=&jOAI9dZb7+a$XWI1Es$dOV2sOR)SK^R{fwq%+LI{>25-GwUQIY6=;8ReUehPblwyn z`KR3XzeMzZey5-`tC~4RlYJiq)gQtrvBnG;Mz2d2PRs|~8p=i$*bz23S9|@H>h8`b zSyJ}D91*kdm%9D_{iH;qRe2y5x54$%@qO{GJlxM93?kfOoqM<>OqukS<&sEqa3MH1 z4kVn*Hz`ugmpwmvcRr95djKeVMeth5>kgbt;FEbcVXq z?Umw{v*{sBCBFh))wiFc zg91n{ZI=!7&G2#^@-osH1)ABNF0ub0nX{9+d7kMT2Hc;_IH#G|=!$O5W`|RsI5+ag z7j|X|>R^WQRfaKH<$9*dw9-O4Zr1NNiziwgcid}LFAqU?z!tPvIXCHt_+!c=14fJP zy3%^L@wbbAj8aQh&b=15G|H>@(z|+qomxsBFKuIJhRK!cMp`T zG&}6JH9m{?830#?Uu?uEHt#^%QQ;aH6(ufL1B_nffh&9xPPkz*Ap3Htvvc&aP*7_( zkoh^}1eGd$c{{7OoE^hxIREshrcihzO}$)(7}+|64{yE`rmXB;G?aojNDzufX~f4x zn{T)&YT^v~b-u6=yh9SqF1p&%7F(;TMKE+U{pBnA^J(HC=W|l(Ya6aA20y!iZ`>fGsl0alN(o0W)=&5F0{ zrFYB}YbFN+75Wl&kRG?>)vF}joC>~QF@krvB=Xlceh&bOYz~ZvxA&7a-B)<4ysub! zYzwe);Dw(O7V}|eR>+u|2FTEC0 zexdz{0_o}c+qYhCHxiIgN8L+#xu=k6m!&(s$I6(I-BhpzMGFPlIT+fQ86x_p*ANINM26hy_sJu zei(=DbMNozM$I12qRDlt%DS0NpZ}6OTj7ITWVse4e~E2h755Wt@d3v?+=Afa1c9q3 zlGl$F*AfNv_d$*@({}1=%yjI2ptthlD*9rTZw)r&5K#3EZ;pXCOCC+?BXAr`Zr99h z4*d~7Zrd(Ap1Ptfb}412PF8Q<^@M?w^F!|GE*&G+9xur2y9)cgt6w2q!^?Gz8eAco zxX-#LT+2Rao0k*?Ck8rGYGMbmB;RO2Fa}}2ym#pU^M+YJ55^)-iAG}}^OMS4q6&6I z_;4j6I>)^0e{}pd0F6wK*#=Wo!ix4ug7S7 z{vfNXnyq7ZrA3jVZ)D&a==p6dvCB}o+S{c6NlvD&p{b!ej6I12N^dF2M7}i z`m(Fwo)`KHsd;H{^9!45yQcMA6yrB;s?J$VX8d1oR+48{)qI#8nx1u+XpuRi^oAC>PAK9>USleW@$kik& zLEV4potT;NDJ!pEb-gBLUQ?iEI?C46i!)p8l2G-4+u}hh*8A1Y8e4iX#R$ zVc(!2mVNG{!ML}*b`~44B8Uw-nfLm24E7mzxD&f$XQ+-HB!0qvJ(s(}wU#FRY4?A` zl>0xw75^LQ(@_C>0V9qBWxYfP2`};X0f2^JYjfN0$jX3>%zQ)I6&m+vzeq*#BO(HX z`{^HRcs<*;={h%ED}uV#Max0&jcR;xe?V%ItD z7Ssum>R*k0pMLbz5(nj7;s-Zi>ZIn`jyt#nRK^l)dL`P+ZBmQ$JG~a}6&-h0Ao!|*}Nj`7lR zreD;w;8Gvkl|^iylp26N4ni3YlN}MFUo-eCOPRzdo*W1DT#uE>n1t-93iZN9);L9y zs#WVBv;>Go_GD}1z0R?5;XmAP=AGJ+6r*yp(oKq9mq0diz4I1aeL>V z8*noLywP+|QWZ8_^2G2l@Gc<=65<~~B5}vPSf~x{t0-k8=j>FyePxGRfMQ(uit|7# zEQb6bd<8Gf&Amlt(8??0;wriq0@q@cBL@|HW{f9dHmX!ADk|;P7vL-$X1QnP{deJ(rl}NMQH5<8t@$LPa^CVQxTih17FfqA^O;z)?YLP?pC5=y ziMneNfT0_=6ry0C~CtWit1jXH1?UO6#Q1y zcDy*zU_HU!D{DNnXEelowL=tXSmCQ^d(-i>fj8~r)b>41_SG+O=mIq*o%1Ank(!C} zdE*hV2wEQC;71}V+{S{cXt7OFbjV26=A*;tZkS2(uLD_#SgZ)CH+?FZcLFOqUx^b` zQL>@F=4el)-*|A!TTLkxHGT&lZev!^^dZh)Bh*{XTz-eI8*aO+=AJm>!T!3k83ij>!{y*R4hU~RB|KZKOGEe;_1OxcE zMhsET3*J$HtU&w%CM@;@^!~rrT$cL>&E?KnRV_haQ5nk6q{%iB;B@@*-V6wK5Bl1m z7vdC>I+kLeQQ-rmh#hh!4@(~JUrGE@$81R%sS0l@xG%z0y(X1(nlSy+_QloALlp`N zUjEgyY4)ToMC->D!pVxn2|`|uS;ARS`LQG=?LaErpNe8#V3kiHKsQAI)1M-^ti&|l zd^xNoDht8`l6-*W+uU%LWeQqgl3%OVIQ%T3sjn5)oINyPWrTqYm&O6qT$CUdOg1%nJ>kXBq|Ll=uOx_swuck)}K;owy%V1SRxT9}nF-u^I&m zF%DVfk#XqXEz4>uYddPcu3Ow@sr|xA%t9YvR^r&YNXf%MA`lV|l*dWFZLnusOI; zyc6sQTqz~dx#p-rLVTt{S*~HlX(N+Ovy)~e1r%ftX*`EpJQO!`$>a;BzX!S2b7s}@ zRDQw0uz!W4p|b6bK!>??`>chxt~EOGgwb~QBPFGIRxXu&_AS5FL>{?5r1{O1sob2sw&!fm5x*GgiovU-Z=Y6xILOX7PQ$d(@BcQ_=kKS22k5;V5gbq7snM7% zmqO)b3k^17UvZk(!C>>1paAysB53~no!dAe5vUv>Z_p92 z4;=CN)4-)^k+-;QJQKkq(|TvVRl-69=hb-p?#$;jSTNa933`JW+d}2@v$Qdm^qZYo z#~o*pf9~^^uB;xQ2L^_f4tR^(zB>F>;D&tE!>GUUURFa)J{BIv7~Vi zD?8yHZe!#hjS%$0+GeeORr2N^iVB%f7`&%rO?aSaO^EGt#jUaYLI2fzC=RK%`VViC0i+ru=}k{fdf8ifg4x`%BmV+H>xh(x=TgBwd4AP)O zdZ^b{@x0#POqYU7QH*Thty}g8{8dgB=oh$hvnREFVGE%R`*{+)k2PwIf}^Qz2!5S& zypKG-3YPB!`bow|Nf{Q33B6^%=hsiGda*jk794&u6q%hLgTLI;8@N9(J3tb7R}(q8 zFzt1sG1}d1e6i-8-yq)M$rG)iH1T-M%*}XTS z?IO|x763=K)4Is}F_azbGK8sV&)Q}R0M5!MFA&5tG@^d)$4HERo^KF*>uS8$3b=mS zNGDffAXt9mFAEyp-0rqqt*uRq%i}HgLJ2dT?fPIdHoO}qwvwhi=L?PKsJ(_Lw5wg8 zyy>iHwi)M{XzN)kQ#k~8MYC%;=Pg6X_dv$v(v!nB3RKA_oPR&3x4*(sBA3jO{1&Ka}L{7u_SY5QuL}v1J#!4n0iTK=0Kr6<#jB=l|L~Oe*%GC5N z-@_Tin;=zx5QCgk1giOOG7nlbwH4tRJy*Qa5?5W)3f8=bwnj9cm=z4nCS;noXAB!@ zb*Sdj$0$ZgRe5v$kg~0%RT^Z(atigVVINEO&R|8lcw}kB^MDC2d+P3+LDl9a|1NM=BL|ve1`R3@mcaNw}Y!r7vofg5S4y z3|=%*xk5D}Q^vOzTK;CklmB9I^ncq$m+wztUzR+meQ;enfD7^}2INOf7p#1^84{tR z#HyZxhUomrsA_?V1;w+ST2i2)>ux%muyPwX(w+PJQ03htLhO5w{5dzcNp8k3pzeW1 z;$6Q>R%V>5FmT6flqZ}e*`*>h>)lAGvObSxxfpd_BLjK;m4188fQ?G7(R6LPKna9#uFY8gMm z)@Q@M%%anI;$uNRRNDz@o!ivZBrR%pCvj_)#htr%5AYI@HnU`U5VSc(B%N+7ten&! z$2=1D3O}-#A!UDb6s|4oy=*giaCO7GZ~1)6Fx>un;4}PK*M+OWr@nY2J>m_NP26L) z?~l2tO?Ej3x}yGAig%Oot*tB>v)`!7pkB`Q6K{kTv!1uOeVZpB^I8pQYn)z5+t;LhhWuKtoB6hTKIDjH!PNHQg8``oo-)6vmQ>UmF;VKu!u+PwE zX`m5p?NSvedC9ZD*4ZW~M2#YCqII{!BaU>ZH0*LIr+CgJS2x`tKGjAq!^pzH@(I;r zr6v0mHR)1h;D`*?RtDQX?3vFP4%1Sd>IU{j?aw*dS$>wyHd;zUrLfxn+R*3^@yS6e} z4oOurTjB{}Cx2*hfgR?Zap5USY7PQ(W`c3s;u~UUa+^(fC`q$dSn#mS+CmhqkuDy^ z?|m;*885XUkR#Ce8#H~Tm7LMK=;9Z-o~)!Xcu$;~BrJ1^>N=w7FzPT|nL-SIX$_2q zdYAd9o_e%%5eqnnB(bQrpu1+9T>=})f~XB|%dLiX+z4B*x8vhL6qymslI4Le^!It* zbNDXb7Xxw$9n2rklX*w-QA={z-V_8&`7Ai+&|vIWV=$FGs6yu5%wBv)-r*;Lp`y!y zx0wLQgTzj~3+MdQzz=4jFp#~oe(DFU?Gv&8_{Suh!a3WyAj1Q*(0}owI<=q>e3Js6 zclAx+A;{WnGEV@^5Cx`iJ3<^Nc+wH@?Umfl3X~V@3YI$h?EjgirC+#s!|kxeCZiRF z+KW7V4EP@&zSx#26)Bf}=vBLz+|8Tj=66o=@d@{g#e0B%zHYU^jVYz^yQ2(GI# z8|g}T*%-?BUDEGourWMI)&csH2=IpWw#4rB)1w~<*BNok-{t$wZ>%{$Es}&-7Jyw@ zN~Vt3EaxuAjwzu>Fx{SCwm*nt~I#ef3U)r*?@WBo)-&4sc?sqNM zC${f!j$Ub^mRButr(6*yto>xCP>o>xYVFsh7vDSyB{8a+jrX$x##(Lmc4z=m$(Itc zx)rgu{nGH%gm}Y&xY_Q0y0^2tO6rPvk$!7Wg|&KZYiG__)T(%=1;!PDC`_X&iCokN%UEk@pO=4vyEsp?=%|5d=xR&l`7tQ(3vOA@C~o1hc*q{JUl*z z9F~-zY$yt(+KbqVJ7-mr+^#Bm?yGZeJZ|;M{E@1{FIA^|E+-D8J*311PIf!+P`!8G zwdSOm!XNe{Z7b((cPi(y`1tq^1Dx6$$>(@u{LGz;|8cKy57UV!U<_oS%BS#LfTabH ztcV2~`2+9XjxqK_cqn3Rukbzp{zdPTuqcSj`ZYFu-^M_B1ay#a_02 z-Kqa6ij#Ck9^83eAJ7}lT;rAw9oTt+vBx$#kiYcBl3QUv?DDNV;DFiwLM9W6`+_;L z4tTNg-ix>y7`q&JKjOM(9%Bz4k&E^)*WXa!=Q;}~J8m76`sKsTy&eb6>3=F)YM3sR zRA<)wsc0H?I`j^o0KNCvpZKQu_UG{NJ>@&K=UJqMee!sKfNHlzl*-3`8|hM3y(mvm z2f$H+@3YEV1Cp0h8ADwrz}9F(QGOlu;#{DTUW-QSM%pAIShYHP&F#tRqhMoY=jlYX z%n=2>bF@M0`$(BA+s!I0@C@Y!zE5kuNTff~H)w!KI3zHtdsP)a*WI%5nCUDviB-Ke znC1vXQoM7rQU;}Va*BIb|K{Z6&)w4hHR*%@YOnUcm{R?ZICK72kKtc`-kwh0Wgxig z#yIeP3vsMLo)zL3*!(+Uen-3Dx$(e8y_4*9c=3R^_9kRmVlLv&-!`OXrYAkxb4cx4w)jxd@At7GNwz|nnRh>_g;Nqm`0q+zBTyzCr6;x*4HPY!Ze3F)GaM|9h8sS)| z`;^Gv+98`|*w)?I`zSFU35+I`eQ*L~H{3H|0M3)O;z%$S(04xZep1Mj4r-8ZP!Jt=jT(A`yB0ZeIXEHo6QYXQCCjc{&F;C?>H5C{6$&t!LSO zTMjI3XxMTcRxNDO9)7(arDZNcR8D;0N{9Q6T_1uT1Gog61Tk&yBGU4rxZ#ZtH97{Z z2ExeeX$!wJn$3Qh?W+(+Oq3yAibscYSIk_lKQXv$;$E>_Xg6G0t6ig{F*#RjArs2y z-%|uSFczWHp)4l?@QboYWFFyM&QL|{b&-_mchfSPJQieRcv|aMm1`^614bb`btcH7 z!h>QTsZyg6=oz_MO7ne1y^O>|73Xrhx(^!Y8w^*_a|y*8h#>AH|D)>10D3WE+D?;t z%{5&FH@~%*SoIbJBJORFi>d<=MQrb-`YNe#(iXIvG5;@tN96oz*jLfxVB0Fhek;fS z15oHJNP7My=;`GZ-ZOUyO98Z975^i=m3r^az836MA&yi0?;(}`>C3)L)K2V%XMhY|^&T*Hy*xYSo=~ca*z8@!Q_LAEYClbABy; z)gi8!T`=1DKKi*`e{{C&Y1z}aDggJ|RW~Id59et{(Z_rBBMIP#`n#%U|G=DQ!ooPB zZ(JG_m|^5BmTj|`a8B~h@C)>;Tb1QdRW-MDMz9g`5^K>bj=ybGE#d`Fl2V7vbkz}NP+xE!(Aa`Mxa^cfWg>x9 zi)jhV6+W=udx#~r%V*1!jL5ZN;q0o*C^EGJ_xTlX92u`%IOQ^Ua{GZ3zj}qd?qyH- z>!wS|0K#dCF6^1C}AHe21+p%;3h+Ypb(47zLE>7@LH?K z8;Yl$y8F|RO*x6#YBB;9{vIp+wNK=0J*^cd6iJ;XMn;O3;)pUbd^rf}rZns|GcWx5 zm;V5}j{!n^jYv=>C81A(0z85Ms3VuO?bNm*A7T2d+s7DH+?S=;9pY=w$`GEJ|5s#{ z12&lqK#?@Pi}zwct78A9N_rs!At#M|4{zY`0(eZ|?FrSH<>(cN<^U z?x^=nG_<$f;WfB#j4ySS4t}d^-t(H~uT!4<;Ns^cHBziL3>8W^G*F+TGk%gL>CDYt zna4QuVzABQSXbQkGNTLB0ui7XdjskER`B;wBTU~epO6q;ZS4z|<(j<92i3BjrYk@X3!s+@@BX66KCFF7q67f!~?a?c~K!sJA^pEe&Z9ysA! z%OZcT^PGzOCALQ`z@I=~P3-jnll2XMO>bV}iX){~vqr9oAI3u8lKeFNlDE zf)GbRq+4hLlCb~=29Pc_qllDDU_eTMK*mCms#K+l5JE?R5UEkBi1a3*1cGz|2_*zl z{9b48bL}&8_MCn8cfRwx=J$R3A92BAWnGK4-t|29{oMEcg$K3JHOBc|mEB&7T1MNN z2jBTsNCbHSY$`IhE_s9i{m^bEsFm|1YD_NGJ1;qW3oHk_-xHTaG(Z7uB+q@dc#5<8 zpAy^tzolRJA4#G6`xV_EOc(riRP*m_eU&{I8Zm+Ui^!xst{D@V()HHf0TRvS?XN$; z{;_vyBBSpe^w>I8vq^wyIcxuBV7)`HL71ePkJGMsIo3F(*HIQ3QtN9&w?B2t@bjh( zwj`ONaNgE{DC+uTe!Dp-*(ZAx?iM$vdf}9vabIi>@v)&rnD)t^8D_36rY5l~GAi)z~qeK1uRa4k(-vsB}g^rc65!+1D;AUYzvZxk}ZpE0Q8y0``pp$0! z_OSQ#;g60<(^{9_O&G8~p+%Hc*Dk0;w>Be#?VTy1uLXDssw6^a|FZ4T2a^%_Gkp!Z z3FrL_F}d*`z$BcW<;;syIuU$50w|@Gexn9S+Dvg2>3@Ga>{Y%uN{mrI46C?G6DOr z;e)A{d+y0)LqeT4h>sjX9?s7xw1i15_x9LUus~M#wv3%F5HH^+SJVI&`9b6G16|DI z7|FBcXHPKjxTk0>=1teuOnu|YFFZeIaza4sY-kD<{D}Fy*~;xmgKl680$Z&5gMF4D zFL#5l-aJl0db8jE!~gEppIFt9SpQ}_eL`uApDhmL-}MgxbzWn`Jm}0Cm*x_|gnIAi zAaTA46QJ?~V#M`FK8YXQoDc!Rk10smwX5{g(OA^OYyJGEh&>y1+I<$irP(nzXJa%w zw7FuD1_?2!m(PV=>@9CjJ^kL>(lXUhy)tDOcehRy6bU=F8m5sr zY}*P-kzg=lv6HC;@URLcs+CXS;`VYjj)`du*qw|79?aYPD$7~^3YF=()|a1UU6p@* zRl@PHXM#SpMc3loktrdWPV=*aFtyX1N2<02<}(mn_<2NM*2flTdNfxE8=tm_Q;--u z-y=wc8uf80T7tRAI`5K%5!4oApQjUB#xxlr$;~Ok1R8}GIyp8AAWiz7Ne@PF(za4d z*FHqOKwm^GKubN}IZYvMCB-Guuo^llFH=NJt;e z93GHH=v}Ob4NNC0V~@;s1-2T<=xtF3(+b8J$yPtD=4pS+w7SLtc;an5y(E6B4n#iC zr5lWQvjsr=muf_}AU~pND?#`dh2aA0&>iU8JugBRT(yOn-&E8fg4{GTYal5t84+Sf?Pa&ap^sZ)1 z1YpumyMT$i3#dkl-!IgPKoGN&G=7q<{n{;9*tL9N`{P*@AFOx%gz{AG$cXCE4~ET_ zGiCY-LQ=c4jMA@P?2Wz%#_OAd={a?bae`A%it#XM^Pan(U2oc*glVbXmC4mU11Y6J zx3!oj{{T>e3S%aKzGKxudp~CQ8kmmTIGRx+#*UqV&1XMPAHezQtZO2&>-%`3ZPDPy6f^9&kO8KTOz1z4!?Lw+{)uZAN zBEj49czqXXZDd&6-NCkH6M7Rf$$)RT$AZcE^H8p%?4``i$uB%(d~-_76lvg;0v6xK zCCpZ@_c$1seefQbtGWWdU>_8e2&XeLWa(C6Xyu_rx~OLEYf;8)XKc_bTTH{LJtW@O zHG=-TQRuM@cq%x>H2Ku}aX6=jUB6Z%w+%)pU1t2fAn zj8WgkI)9uCPI2{KV`|c9PhHo@_QUP8|LpSp_GfEKK&beBYZAi}(K7hLgM;u6At9UK zBR2p$3rq)YA9BlV1r4J^0cPGi=7~4tvh~3TpO4OSm@X3z1`8J5J)Mgl&6}*H-6D-h zGh;)6ApYfvNb??ikgw+A#XHw$qm_ILIl8?Qx}C?UB}k?3;$-@d4ij2y(C&{*RMVy{ zEKK5Ymg&;RB$q~AuLwl;*q9{TNg<}kxt!70is8kcF+#V^ZKS0H)`|MT@6}i(zYNM9 z;RgQ*LfBsedz%kapOaS&mY>#vwDw6xs>jyWLoT-!XnfB6`u!(g^s&)YJ&bZ$F0leOq(Zdsf75{q)ZUuY@X?{f?WM2P| zq;LFo-Tm)w?MSD?A8E-<)$K5);iB0WUZ5Hqwws{N1HeBk8e%+DaY>(Nfg;C|GbdEP zuF-jFsbf9ybD8Y*H$Ij&QP_Q7gVb#Db%sk*fY7I@*RA7prfy07j6bfSYq)g+^DZ{D z9DS1MLu+pk-P5>8)m}6l(z+xOk~?aPDj3`**=o`$j0}<<-JCFJX5bX4UF(6ZF7qfe ztRCH4uwYeaiK|HaJd@s6vuQKnwbEWvm^imFbj8u=aIF081YbO1V`Yu-vM%<=KJPJ2 z-M%8_Ac=-{{a)`vIeRsO-u022^4?T6qt_2K5po9($eG8GIzM!h&QPgHZDCl^tLhLxaie$qN^xf?0g7AWE5%I~QVO-) z+EAg*(RXz`s(#g-Y#L{H+50|9nI3d%EE03+`QlBhQX{R3MGKtpO8fr!C=Z01OPkz? zK^-y|Ct1ec`8ty%@a~pW>^5;gyG~w3Bx)O1!5~^}x92W$;3V$mr!^MTb!AmX<>U(c z1or@-rLTfQh-o|zWk0sqNHgZ_90FJl9=dglSO!>WZ2-AW@c$(=U@!CmV8Cwxu3K;$ z^d~1x{{8Mh2Fk+M7BactK)yyGJY*_yL-@eaC!sl@Zj*vo1Ngn$5W^NT`x>h7uOt6+ zSEJ}}e-?0^p?|&3mxD2$J&ik6y8%P~l_=MJ@^0t3oEwb?-2~KMMx4z*?)mc3H606! zZ@%aG=4R#R(VWqou@QGFp$0it$tI7xfa!~(q{j+zOO+#i%TmA-hN}emtyH;dI;=o*OB) z?UhM0dQXeZQ{qz65~dIa&)4MSc;QdlsfhbiS$}sr(*OrX}BW24uE40dd_~6nY`r1YG{N< zE%c=WGqrKB8XI$;B3CEdGHchpgn#W;-I4pW&~OKNK8aNQX}AQpE3xSuxfokECi!45 zqg6S<&dlw+D?UifR<)Y6Z6DNFR<~4&recOI-LC^`^ad5Y5X`$j%amqGZY!)|Cj}a=p z1@^ul_6o~>3Tz5aLTEW`(4=X9;d$A^$$HH7$4uN>lEFw~XnVuhGSGb>XN5RdfpNKw z$$&GD2JVNqLD=5{CT+iQ17>YyTLD5knmL=y-7V3OysGzwhX>5?{Ohy+bq)V@Z~R~M ze9ev===l1aZ*3_7mo%|8*27N#QqA-P>xU_jQ`Dt9gV)5I#IZzNAJsAD?!Dr1 zXV|iX)d?Mxi&|=*VF*h2`X_AAZhCN6@are~D_RNx-cy#|xT6MzQHl7zlzH3KB{Id< z)@4?-Vp@7{r=o#(%0{16pii0Q)`dI_$%BE4rKG`kLZ;x2Qp_5ap1!_GGW)c~cXX5f zX2J-xOiW+oE@~sUqN6|H!lMDnN?tABSkZEM*8cG>5=%CtD>&Gy9a$RWUWy$^PW=?z zdwevFKEt(LoL}7Z_wa`Sxfu!0Kr=0-#P>{YHf2Ubc+tF57{LR&-5@77_NYs>HaQwv{^O^@)lBI)xdWY)!1a#j>tkG8oBD-8w$==RSyOO=U?9}A0e9zDEFccc9`=H7|x=83srtK2074L&1$5olGoPua5w-*jsbSrn4kXx78hwy z&U*02ryKw6-kpap^E^0odC!x}#}DgWffj!k`TgFHc}2_bEH2-@dqTD#D(UvmJUjw0 zb)Gv@yMMU|-O1d12Nm#^qU$xT2r)4&8OMY4EPKuDX)T4$#jXNwHp1DSIg7$3Zo&dx z2>ESyoU4zc@6!)li;n^=M$;z?eoj|w2WIbWB>m0~drj>{cxzrlLL#Nl)?Tw%855xn zjQ|<2Z5=wnpCR zpN^Inm`)liiM!2TlD>by%zNI*P4i82Me2NR^6J1wdHI#Z>pEB&U4^AoLUOwUAmtu< z_R@*19-xWk^)cS%QV(U~CZK!Vi2Nl}Wi+X>&`XAS9t3b$|~uY`I&)~)R2p9SEqohdwsR$Pb}>^#Y3LarIMxi@y)V6ivflo z(Lg+i5RE?NPvIC(a&V8mZA-=GswGk>NXLex?T`x6a^eewnqQ@cZfV|p&-)=&OAYLJ zYTo5rmm01mdpP-g_Bi~$T`SJSY#JS7Bx~8zCP^|bgcT0Y2NT2xMm-9w5Cz6}Sq>i; zK(OV1E|dFj=@fr=>~C-{5u#yXKE+~98rK>|EW1^ZYIeOPHfLsSgAA_Mh240So|T|% zCa>n({r+~M&Bbq*o?0JJ;IoI84sBDb>O}-?_e3;0o?T<0qE4R-mE%)8+Hs{`q6lG< z8U?}%+^#6Jz?w-N$|UV2D9xO2#Ect}^qh&>@eaz)&HJ|jjn@FyBLgsD8v;zf8g;F{ z@O-=v=msbU51q@O&t!hj1a*2sf1vs%#_tP{Hy<;G3%=3K4daTQCvxv-Z-O_GS1<_! z>`%zC+hO;$Wl_DYO%BH*CuhS|=89g>2w~o?jswaZv+oI&Z$ttNL$GZYq1)4Pq1-JOW)H(g{Ff2Cz=6m$Vz1V;0v;X$%e1CFl*F$_1 zY-yNB{ZY2=YdR)8?2(pq-~?QFn3>ufjX9K{b#9VXyyFI8Q0t11L8xtz8cWPLZpws( zUV1gmNu>(Bx^|mjoJzWyq}6L08HEhKo8C*Xty36se+m2>{G6QqhHWuPvtSIFCUUJ0 z%dJ{x;4PjZ2OGl5^yZr;!pxdFvHLSt6U_Sxg%lJ% zth~ob+)0eL{9*Ee`RvgT=h80b>k7uiC?#*Yw+EI++9FC-y3m|gT0n!jk1a!Uj@CYa zx;J6px@3?Y+zsIiRz%;SZ#D+`+GD0x*wPG)M0O3`5oBGkLo8b-@{h+J z>6*I!6Qo%}theI5shELo>!HyCBNZp>+v&%8ar>HOwK7`AObNBg3Zqu#(?mJ+&}*!D zf>}gZ8RKaJR>XhpUg1dg5GG*Wp{M6m^G2QAl-gtESf;FT^F=D=Zinq#iJeR;{dONE z`Iq4HOg$^QNF?_>bI&BO+ST;IqNGje9fa_8*I*&k-LA=x8cxK9t%?pgi)v#bxWnR# zLcxcu4Wk5yZ_^j^jS|(2yi=lFjqWARWZf-L)2vR$97+l}+@I2<-#=A$)Zyj=Hbd%#U4gxWJuS6~WIWx%1hcw??qhM*0@V-OMAsr~DmyBlC9_ z`$3{5x4rdrbh>m3^X};?jr$thjrTx|ByDeN-rT~yP5C-=EQEQdgK;(}6$tKdkl>_H zPjQ~rtIs){p(Q3q*78m9@iVgL6+K5-sR0+UzyD-C&AyW1EUUkPDgD zB{#(ir{ZiSf39CMpL|e~ZDWx+D5Kt$D`HWqr=C&mUc?Xz9T6;{;jDR`8yhHkP*gVHB9g1nO}1arb!k61G^r-s6j z3YbY>=J>G_51@FRiA($y#1PW8;iSDAwnWjoiU$^6Z~EOsg_V~%xu*x*7K>bUxC?xp z9-GlBWuco+I)VC~0bZuHr*hX=UR!7xa((N(&d=$<)E6w!6$Ey!a91B!oQ%UPUS3pT z91~$Z0w$8Om~FSG%nVRaNmoM|KTU%CRVlM^xlhn*zg?sbuS2hX56Q3p7Ra3-@5l_f zIp{V5U;0Z6rjCLE$Tmk&ucw>43$ncdkm>7s)^;s82q@Hfm{%#W5AlF==U(c$_0`qL z_PRA+Am{6O%>l*+K|o1f+!#Az$kZ&*h2qPnTh$9+@W zpJvZP#o7K&xKB1sdt*o+T0ZPWPDCAkdR0L2d*Bdrsmdx6S*0H;Ub%s+K8xI{{ODqB zhPZ<>`#;9MF`K21R^+6vdxRuQKxmb9^gUDS7f_`QHspuFN9IV0qa|7* zQ%FaO$fHvg_4LdzG1FIlS~8sCq61Q|dXOrYv?ooAJT2z+mA4Yz62}ZaoXuYTa6WG^ z#^grQQ*>;~hvnsyo{?B1H`DS*x7zPaUotaUjgMm{t`8a9gWL>mzzAt6h(w`XC!j*E z+A2h#yM_aVcZv*Qy9`v=tM*N9Hj|H`Ptmm#X=DoY5%&oBYRQ5ITYCpnFn>V<+DP2} z3H4B~`!=!rCrFdcZ3n}Aw`74e%6xm0Kx9O=;g!QVsWUjyr}uEO$*_w9uuem@yGz_Q z>@h`G9bA|6=^3i4y3Ki$ftst=i%q&@(XwFS6C7lGOO)VlB%{=9=`pCbq$%TcigS@gN%G? zVyffGxM~6$G6>Ba^9ZD>3r4>l-I3m<)lR$lLy-RjVnY1*ox&?|xbXZdIR(;}ThMeA zDkpWi0vo7YMZ8R$T*ruE=3>xar+;yg&@IL6;VmwN)6EIvp1v1>nM-*OrTKzKyL|^2 zqDLoi!)F`1*rKTNFFbK`jNq?Et)M=8-U(pqmxvSK7{j2ck=Nu4%cR|eL^+&g-k*T) zgM;iTS64?$=`j?%(JI+8B{PC|3|~@La&z8FMEE5l`O)ZQp%H_IxN*l}&t|qP?QO%nG`!0Xc71cd&@}xgOa;zZBr-cJZGO$LHG@BIT1e{d zKzd2noJ2YF)q{Tkxc^y-vOl>mH(^lK1{*!|Jm1FFP1H9V;pv!n)8U=aKsq&XRLR4~ z)em_d#@melC;&T1(~mv!TC?@!`3nllBv;(s^gesh;rldlgE8~;=2AM%iZYl*$Gn3c z8dPx8tdj+Iil{_>5u&;aq^gqVw+#p5Jp(6{_!dam<$P|Ff?|c z@^NkrNzLL1-;>2E`ewZyhIv@ohB1x zG09z77>dWzC6+wFeQwd~T4o19ec9%h&WkQ5jOPIiVAyJa3lA9#sYW+teZ1z~bgg>T1? z8|o+<^Eu2}S$VnmGAa)gkoV^HtuGq1oY!3)z0Me<9+BNJ#R;h<%2f5?eCdEfJlsE;X2vjM9$;x1QVx(G)$f#$7^pRI!p#Se!&M;sKs3oc zUENa=tI2{~j%=zwKjg#lZ3V^|Ju-dXm!LN)d#RF+p5g_g+|_hD9k&m%Ia>+#{pOBG z$AC_w!q#^Hk1;eicWn@vw)D{5a33r6T_P5eR@Y;}OX~o77tQ&dhH)b?G+3NKBRpJ( zsa#y=oE~4iLA>Qx?3P?T{yNA%-)$%$v>3bYJ z6bgNa)h&N?d~4MFN6t)~$9QC*Wbw!38PtG!pmbq6rby+iNs=cgmGg9ijIcLgX)Z!- zw+Uqyi973GjTyTx1>wm`nh&Pcpp$xNIY960l0k}`4IuU93q7bmHF6&Sd)JqK90T58 z>8w@k_rL{IoL0&W5yP;LA>iz?Y?kd=ptni}jdEUC|10v^$`>A4b3UdC84M=QnGnF^ zmjo)Rc3CLCoNs#{hAA5!^sl4+(RI6|(eh!)u&ko5==Ndjo3@voU3r{6dGQsngZz7* zX6W*_L}aCpb)Ns&6mKV(R$ye7T8opG(UkI6^Ia-RBs;kezV17khdomCGQo5yuFO6_ z@e7Z?Th6WTC64*9RM`A=OxTpteJkxq&@;tK6K7I@>% z&l*2_{_MHw6j)g2pH6lz9Kux39-u=RCppiw&o27bpQ5ic?k&Z?*HXiwR9DP;v@E7D zyT=x}0=qs>F&M3PI!JmvL~WO-TTs};B69l>ju`zkr@fOfP=P{U^4%5*En5DOwj`3Db;Uc7SJz%K=&F97yAoBoCRN=>;j&^m z1Fv9mk3hBY5gX{h`S@$L>lK&Y-56|3Y~%COS#}ktN~9>1B9#!^cC%UsSm)7vOaxu7 z86$!gny?KLY2}{Rm>=}HU&M^y4xXYE-yLakkkiS;=jlr9*bEWirgyK2xa~=6_|%z6DH~@n4v- zX1{-9%5nl>B^zgI0aKPnrCda-eQpCxS;eQ^_{+8Ma&q{mbH%fvrABFPoe5L>d^`gX zIMt_kZpUCD0@0C%FiS`~LYWp<@F~qLVXVWIyPW9oCSq9qt^uG9MRm1gh|=n-=pqi< zM`^-OOAx{~zSt?g!{OS!B(<=gmhZ*{+1|Jg4PY=_L&Sm*mgy_G`syyewCQsrJGu$Kq^&R9>;T?B9qo z&9_iId};W1MA^z;i88D2>F)6u2A5|t#XUS3gE9cl4g#JGw;NU=ra zo2oetq5{^Zk9Hn$O8-#GJJtz z98ux1gSm$h0k8`oQ9wobBfTNKE)r@zD&oHqWt43f<;4SmxQqorl(~N;%AQ?47W_dR`|3yd{>19uQxEpe>22hkbNS|2qEPxL z**y7=O}i{i;yxPj@O%rC<~f-5WA`5EiA)Genqv8={tPpSLgZuiHG1SNkbVf*3{|nc zgt#7W+Km@Wm%dpZdE-@5ptW-!Ueh2|3?E~;TJmGkg-}zx*`xV->*f|qqh3p2xB1~s z8}6lRIXR`mDWv%^*KD@QJG2QWNBbMJz<{!XAZ4?~I1Ivzj}^!^%$m=*K=+M&0e4f) z*BH6Pwj_m&p3hAc?^7sBNo$kHNS0R^pT7H@?0k2zg_?fC!kOhM;oj9A8^$212I1t~ zaX#OOSElov#~t#nrn`7aDv7)wae{l@rJg$`~eLa5() zsnieS=vFQk+3tch!CJZ*9hsHli_RmoFAkGd>f(bgz8swrlYuFEgsuc7WvbS!ti|3! zPI>GdM>U!;F|HIt(Z!bS(_y)&RBKvseU^u6P0pO?z!){=Y2kv6x0gzDVobhY?!sZ$ zHM<-GUxpRjdHlPlN&b>AaUZshrS~}B}ohM!)&0Q$@LLB z^$%Vb|2?;wKR!4w@!;Yn_Xw~_ueHF2AIhIh_tT>brzpO>V3U6JT0au6`Q5$!wMd1k zDtx%HK${qh-^a?-@63jwAGekWeY5bEvM|jYmCz28CcLH4K9MAP70o%7!WDA8jHiYd zuaeASwag4#=2ZeSv1HmNk<`jX*9&4M#R|b|R#*_2k7f_Iew86-v0~Xjc!WdO7Q=|N zk;h+nW+nh6TE`uPuT9fZfev~MObw<~UrGxk)_mcq-t+(2&Qpt-pZvJ{A@of~2y>a7SZGOlm&1Gcvn9&-$4=ZfJ#a^J5S7xy0~h%f};(@wbc2r%mPsLLH@%ykgu zIAF|CeA;{H;hY>G(f^@o>>pQOzXu9`-Se9-e{N$y;F|s)i8o_Fyk-8Dctd~hqX~#N z&A$?F-b=4YL4bHW`y1lTZ^m^@PQiXW$#zM`Hp$A@(l02Hu;q?{lD}0(Dly!dJ(I@Y zvK@h55;K+DfCP!DOZO(A4*|7c)lg;jjzoM^>sZ8A@2@DmFQF{4FJxJ)Y2TE%gc$&? zxmA;JVLMm9I7=y_ac(a-;qUpzjs!g&-zu)4p_ac1~)a6aVWr5*lHtU$l%1YJu$Bu)eMdaPs*rw<{*uw zUx_!HzYuSFdm6hcP{ECpospEPV&$%|*usy=r1bTADU|n^#+bmdfYbS{yX+B0wLxV+35%g(@}z`mv>j(a2k!#|!~H=-{t`qYFoZKaYUjL7_U_NhoW7CO0J~So#^58()s) zq^e^UVdk3=z&ic6-Q3PgeBIr97Ce3-e%7P;aU!<)xG7Y`#JS8BROa><9;+`r22a<$ zq4)K;b>Knk_qEXrp2V zkAG4`DmDoi>Y+3pXLA>*ofM&{GU-mQL6oL_M!gLU1WAgB*(F2rTq4^3`y zTAMOyKTzea(Mp$E3ta+K5<^2K$%nYzkc#D}IrEi|#WPZ~=SWtq7zt}vhVbjpI!Gr+ zr=6-a-M!bd9-ANDjVP6vmZc*JGB+A4H^1_3_0$?7^PcEFS)_tM`nBY13FObQPwUl~ zfm6w`M1;~vI@F1{mwlA(^ATFU($EDEMNus0rPT8iuj%5mkJ#1}=mA&AUfpDb|C!gd zG`|QPz_?M_cfE;wfX7pqaRRxG!TY_mj*LktWZ%Z)f!LJ-bL^5vYs$I!{6M*U-5$@G zIIB9sg_P8M+u^*LEBwh7gB|%Q?LbCws%VgBQ zl8;m7@Dz6em&AygHi5GElUb-pK z@d+EXj>Fnc)%B?(_ZIm+8B=f}FX^$-T6-wPr&<6WD8ZEjaDgB?aB3x5qcSqr1`TD_ zOhF$7OZNtgv9Hr`4TYb4#`NG1-(tSSU((ZK`b~^Mn?$uA3UMF)$o;OjcNJ-1{w6t7 z#K`Vdf}Mq^TiSOp)mbBz@4EJxZ<^aJ>Esv9JVskKF>8{7kwz4t$-sh z@KG8u{?6HMX4WI4PYH>0~m@fo+MZl;Y^iD!&TPs^TV#6_7U%R364?zMzv*ni*y#&T$F2XktIOZGvU&jjy$lS~X19ZS zt&t0X(igdp^%|5|D=lz#ch3?qKIG%hLFgCI;3KbX9tzq5n2kypTN^Vq#1V*n1m7e_ z5x27b%F{t9cbPTZ$IHiAYf4-M9}~>0ww7*7LG}_?h{rH%SM|!**ihCBOj8Hlk0UsG zadQUF9z++iEVyHEekcNdh-usytU~j9z`lT(6!%)QFMC6)L4;BkC~L;Zi<8x&mDnIi z+-uG2xk50lk9QI&1?S4^04DFtUH^4dgv|7tf@jrcZ?(+Q zVFNGc)cd!a-Cln-@v|#9KT}zJIySr@w*A3BVCVi0E(O&gP9$Ph{kgjV8f8p@aI@7^ z1V?6qJ0|$pX-nDM=B**_3v+0p?0XQ{_y@=Tr{ycc|NMFWaUb#Pt-RyQpWD-L|F4W+ z;!Nt_7(dLdz@1i>ew9`~*VPSR$0|P1Ms4lhoodt)$ZnQ5>Um!j)sTWz?khK%FNyx? zE%V-_G+PkEFk~vw5jU9cK>n1>p(^q5M9f6Ap!uN6m~#X1z{)yDb`e%pM-vI#KpJiS z(6hXfRrCBs6-%oR6?|G%LKrD%=vNV3{cOq5#w`K2ypY>}8*AdgNJ~t`*DNxs(yLxa z@BcaZd`z`h$Z5>imU3x`HM{9M|&*)~G!1Bg)-bfQA z)9kV^%hbSOm-mUHUhYO}9ziz712U3~h5EH#75Fe=0yv_BA{98Ej5Kc7XVU}U20$7i z;q&>$)60pJ*l(C_mvj~Q8vO!zJNi?E@EPe6h3HppxcNapy^oJ`-uPBlx|CZiO6@I( z(@z__ZqwG{H4Ym|Sst^m#s5@tU3Da4GcKyOcUWcfIb;{q$@mvydDHlbTBgB-4sE%R z5~%<+7-V10Lq#@cDAHBNqjUVp!=eX+rRXtLrHhp|yWp#;Iiry{H;f zu>eHhpoNr=h>y_G7MZ%S>^mcs#bfmggGXGi0G_WtdW_&c5>a&9K$P1$B zoH6Ry*vGOi&2n^AXU+nw(<8-bC_q7=3?>KC+$EEZQVyMq5|Ouvn_pbRWRCi6?ApbH zf`@|v^U?iTD6jbC!kbVMNiuZr!}ndM_D<>C=vqIcMc+;~l_zu=^Qn-7^*^>0+w}qMC+O*NK zDZHDJDoRIDdMtR8!S3>)sm#M;%+hA7^KPz%B?Px^Lbyi>UPidltTKiKt4)=v#9zDb zYq3!9q_~Uq{!HG7o}SBI%{GI+5taGu_udmzXKcq3muuEE>j!Jr*6}f76wHzi>n!^A zV6m3o6gh+jMXz67pr*0Jcd&`~ltj zj8Uv(UOTou&(#Lm%*jo@=d?RJPiioD5L=+=%oVDZ(dh;{(<1t|0yn+lK~h zAD|e&vVHJh**@f7**<(C@I?wj@Y5~JkrXAN^gWmR@sVAJnC8sVCSl*|*~cS|qLxq4 zmkUOkg9rg^F;R(;8C~<^=B8Mydg=Z6tAA}BY zN}zKTt}JHq8kv1N2JCm0donDXxNbcQG&!I#9Bt%^Sux&x;mM9<=7SjqK@2_O;;9ij zh|iTc3F32|GlAUK;|tF{J|+@Qn&QSNQE=QNhM*lf^EuX|2}(JGiUdO743NehLgaje zPU10$*ll%UL?+Wj4e&16ahHgP{|slw0sZs?E4B$Un(jOy5~+2WuGW$Q)IUD$&K`m??IRt{R_@BEEg7r>#We6u%8J_+FHg3ZI+dLMBB9!~1j{ zm0t0d|K!E*+TeCBKGGz8>&{?YWlUG`vxJu;u-w7Lf{g*L{^^T6%*45q{ zy?ij)YfJcbyS!)JN6N+1XGaRlDtg0TCczcYc1^dQnsPg54jJ0u1Yi3+760~lT;Pq} zikTE+KDSE0fSBY`m+HijN6GwfvgXp0E=r zZh__W87`%`5{-yM&q^{npwD^1XtF}yXsa`hncTQJbWh+FX?Rh?r{iN$LFcufuX?S% zzan>Te{qPV^!-Hl^ERt({$O73M)h+2+Kc?7zcY#bchLD|4%` zr-e|djXp>#Z?V4i>WA1PJ@NGyg`PH)C7KS79*kT$!gTzhDp0|oDd141|Iw>bSVk$1 zWY;2jgP!~#Fns#*Ng;3fY_C_h5>MdIv@K+xuF3hrbJ^Yx?(eiQCZN(MzL72?Vw?D5 z&+`p26?+H2s1L8^A9X}-*+{txYZ|MNR1|j)$QN|kOQg;dNp^q=k

    Yu~{Ud#do2gjnf|i@z%ABzZC$GXiV>t=_rCjU}TZ4JbxBn-nD0XbyfTag$ zPuuXQA#S@c=-u;(kK{DcwJ}+ock8ZTju)Z~rbSYZfv7w7D~@|n*W53EIe~xPV)mTN z|E_!LAO0TnPwvKa$f`BK0b9&G)ncO}L0Zgq-+4m1$b;SNP*`n&PU=)75zk{rc6mo5ret{7Q4f;V*Nz?CA^774g<%tdG! z8G!9!nDQa2S~gRU5zf3o;R}TvVM|Yuhi4lcgg9931I!XQKU1tZQvl!f%|g<7SF#}6 z-bacMC1S|QEtSl47-T~!nS2Wxcg9a-C}^)Zl-EWY)g_NKnddt^OcZ^ZZ*-$r=GH<> zU(_k(6(iN@x}8;K4-KV!YGx*Id;9VdC{uEM`bFaX*mg$x3ahhld<{VbmCP}s3nUC) zVN8{x?O=c+pl9OJg~`}=2&eCriumrC~v{KW<)h zCA=a??j3h;-Jk*$xl}8c4J$qy#ufNXO6tvmZ)7FDM>D7 zw!ixs^{`>va42)P(gp(6)FUFGs17p=J)Ka1mNmAlO1MMmKRuA%FWFD3EKu#P{$P~Q z?}w->DJ`feGc3gV4P|X*(=7WY#keETz3hE71BMBGWoeUUK-mPs@bY(=qG&<7(qum< z*R(Y0*O{i!UG=F5KiY^@lJgLrZzj@^tqR7{)+=xv` zjJ?Y=VW|aoapgJnrL_h$_(WHuM;QDNz`cu4t~HV}h!e*9=C~5ct&j@8rf7jvL0O~V z>8RLqqqqJrTcb97{8J6}Ve`0Jv@@UT)7R(o9g2QNna<@d<@zj_otB-a_9;5c3^6#e=m|#ue)+saT>K(&oSnTMXrPR98p^{o+tmE22G}%1KXTg zW4oC!ar&NjPuN#z&f!`@o)je!lo7ef5<0xb40{{E=?bZZ=Qi}|$d|b|d{=H&)9XHc zJ!QCrdSz6qwr}s92wj+ImLg2oGAhlUs?s5{C~}7*HuRwZ@m$5XbU;&OZlIXsfq)#w zyi;OBaVP_ZeKoBzmeIA8$%_u;VAsVju&!(`niEw;^;(U^T^Y!r{P8x0qiSR19(-y0;d|vJCEXkm}LigFZu7i_qeIv6yk9d=QVkNL7JC+|&q` zW$^l^w8*!rqQuCVYG0JXp-Akf`hnWVqBINHe1uKWSthC)f9hD9P9b}rf|8|gtO2>L z$`I8+-f3?W8^>E%L8T)rEbD?yC|`Ig{g!MeyFvj;p)HI`zDBotSOE`#ly|-3JA@X0 zpmfy5W+j|^3gxy41L`CX0TiYsvwYRnOc_bvY}FuyQEPc~-+3}1)B_xh(RI91S+i&E z*kVZY#m<)r&a#OGA4=c!-;$hEIWySDJZqf3;%=Wla=KXRX!Dp?gRDmG=ae|N8~9Q+ z8g_X*CkMMOy#%F;fVMe;D~Y!5XCo=ke2ht7cql5(Ts$3eMO5kW$!_$HNxrb{GL(D! zghwO%s9VaV%uw{L95yd;@K$&5DLW?AtUn1JAxaL%2f+~w!ie4KZ;a03j<$SqvA#U6 zmNqNlY?))`6rB#h@~c_uPjsDC zY5pO8{;(%_H(yJ_6mV66b}e^v-6)W3>_H$-=)BP8>4TOp|EX2znU=DbjYX0;1zf-~ z3kTQB{Wt2W#?GwSFl@3rL7U$O=rBD&X|9+H$a5&gQMHH=?hJ}dmwSWRRsgXzKY|sg z>j|ibq?I_wf5>Da!S+mjtm`yrt-qoTkL?=)Vt@dsZsRTp7ahjFco8#4xdS$l5Wt_U z2O2B2e&MMKW9u(NxRD@<<|tSI*FI-~LC$v~r}~S7`!g%#dz45@3JkTz@Mp{AH7Px* z|BJgfjcPL6)`g)EQ4wPUA|S-lLR5s53Q__lDk1_KqM-DUvJ`1zhzdxAkfBMQ-glgH@7dpX?l;#>ZrqEG%{W|p8 zt#2XBgO5^Sr)2pU%D+DDf67_Bc91NrgMQ6fIa-(*{`Lh9 ze18mlEMG~uGnLUW-yjo1quIe-6gyG#2+o+{SC&wpVBFN?H9~P z2@&t+v}-5JKF1XPU%n2(&?c~S+FB4&O670;W%<{jfc=HS)(dBRbANv4t=cSdCf8c_ zu4!+7f4%mf1Qk?dZE(k|{PY9`3_~H(6>rklDTPe!pvLg##w4iy%i9En$~u(d8|+^= zbkZLdK;r}f4_oYR!e#ezj$exp{^dKxPiZ$8lGYou-=l!+rxn4=uV#+DY2NXl2VeT~ ze{mP0{)g@VPeSbb|3mBQvP=dXFV!;Y8}NJ+Z-4B~N&|f%>*v>rhkt!x*7o_k=BsPB zX=UX6vz=-|S8O_ONu$ks%aSs;iq?djL+OZ3Pxe&Yb~Zt%W$N5HHp%}F2O0VA=NLjo zq<7An{ck_?{!cCUTL<*N?X4GFtGDtKUE31B$o@zKuWi~t=zVbb&;tTXt=cNMKYHDp z?T`NHVq*U9S&dV0aOdYp2$U1c?mY==H`<%;0El*0YYS@U)^ULB@xPHTYq#B4 z`k!AFu7dx~cff!3*8DF9kl8e3axaJO6|SkmdQfFTZV4q`x29|pfHm@SQx}gzuvA3v zV!X{9>XKppiyyu~I23UK)$KM);%@wCQ1F&BtNKpG=#^0<`9@cD?d{$k@U=SRJkirS zalQs#f!5l-C4rX2JtITD`{{v8dJ1=Mq&)DZO!pWmpH;#)>20OM4uh=mU01?cR*)4XU<-8A7KPjtR&Y`vBc{m%0<#CJi5myIz3z z+Meo<9?pI9>!&p&qY_3G0RHlRPa7X=c=t^B-Vsmuk-pF8rahlN9&q_Jt=RNPq_b1e z5lG;Aa^Es5^N(Fg4}xR%I-BWlV@5qapAi=%xGcZP@95!dL$D(yvHhwf*Sy+aWuwaa4L8Wt1rjc+r&6hZd22>fG}p(a3_U4&=SsK)&~eMK7@=nImR#j-wM$NZseP* z3*tmZMjiF}UtM}bHnk5Xb-n(@3_W!H)TYe6@2=%gIF?v5gQlC$)2mZmPc8L(lo~{S zJz{P3TpSaOdy0#*YaGGW4c4au{xUZpySZCG9O6yWkvoY$gKbiC51^QN>k5%9Ep6Y* zMo6_1iP~7AwKYIb+*Q?MWo+cyw-9|=673c-E8iFIjp?tTSw_d70{pq#-79yV-}wyk zp|Q4%S$FoDN3PdI=I7xXJ>ief_s3j0Q}X;%eequFh%h^b@f_2&cyWM+hnDXR=Z=Yv zl1kKoL-l~BTV?p+8bU&w34+IR5|xA2_^kwH+vp)4p6DpTYyk_;GpqXw`lHj(9-NFn za?FiBZ zM%?rbrLDi~u8-KAEw_;FQsx{EDD2?W24HGs%ol_~#QjG^lccefp|F+rxp<-H7-)}) z6rZcd9SqzcQp|Gr%O0oji4_)Z4?j94J@9Up}8XW32P?l6X{u=kwK*=kzhYyc3DYK;15-7OcO{L5;GSWgd zhhs@s8RQBl6{^1goYgllin2_jl!*d?Xq8VKd}z_GUk>?}{~>^(CYRgb;Gt@0 zC%M6gKX!kHR&cC=3PDCSQ!!=BttjCWwh6g=0m7IS}@p_T}W4OL;y zc@TuPFH|+!PTmdGYMK!KHGW%3b!bAfp^R^R7w}a@CPEcdf*nG2u1DGQK=n72O1tbY zgiMZ1ilq`A{>KklD33Ex{6<#jL-<&hmMnh55)w>O9J1kde^W}GRO{zB-#ndUvP0jX z!V$ED&fop8xfSD?c&PJy8J|S`Du?hngCX*l63V|{tiP|7mh8Xu)=>Z%!CJ~Z~R zI{!<|4R&4QY+OuS-lLSe7d7Kf?b|2k?|Y}ZVYLquD)?6Js>~)D2^a1lZNV)<@;1d8 zAU{DoLKeXxyDW^5tnXAnJoSM=P9`1bS6rii0{z=;Z)D?@4+dA*^qAF;XD`|hHiWtQ zPBdO!hBdZ258Mko_4MhkH80*-w75Lg-TXKpZ_#C?T=_?rr_1I$*InG*r}@rr>*f|p z=n#^Ok1NR-(@%&{9VEcT59u$!Qj9c-OHSl-xad`UY;3K5!|H@EkzJ=YMVC;`@0eSA z)9fM3HLN&{f4EAdo#t}EGWE(8+MI+v5NFyd4~yID;d0=?%)az6>)j&ie*eaRM~&f! z{bm-PebYafi+kOXWfN;YKdAaTGyJV74Rs%-$ugCq+A-@C7_oL<j5@5vTQhv>9tNT*xh=U z5hC<)Fruz7?saK&uvrAo+U5Q9$B1?A7J`u&mlaH5cvoEmHh4U$`$zDCdZ6n=j{1FoU4AwMAf*vE>K9#?1=Hx~|tAI6ChdedHhnai^G zRh8Ph_diaF-K%1lxP8C8JXcco?nmeAkuC>nC+9>$bRHyrVL{u>o|kMfJo}(NBb#51 zAEDT>Dk}2nL2UnkmCE|Ae?kKJw|jj>c!s^0gb#q^5>tW z2xT*8F~#NIJ)X~kB)PI3{#1K)1A0!ubd>ss4}WjgY8@4!L0KPp4pl&&ez#6->K`pW z4IAG-)qX`nP12u-7nG)1w~QgU{de=fLH|j7wkpHvnBhM_CiVAVh{~Q$o;yJDYmr%Q~AqS2l8YY(Mz4eEp>6=~bJ4x0l`u zRsTn5sYB|v$9CLVvuj5}^D2`yyI!CMZ>jzL-y5~7Y8toHrnDCS-7EgvJ6^m0#4Yvx z*E=+}L!8eq&fQ0L|GSsmm$+Yd_0JkVYD8+j|A6*b?S7E(w*AmC?fD_BvCR8RjT2tcH4rgE8%m@aFC7cK*OXcN zRqu@NoeRg!bbE0{Oq}UV^E4el+x6_uUoExYe zf%!MRPQyo=lgb=mYi&JbPv3rdN8|0w#zbZ^br(kuV$WqI#^eUPwV-#>_)Aj~Jg;CW zrX2?EwP{A(_IpW)>EJ*KN@!~LrYZP(`y*1a*dmF`xjkwFJ}FUkn`lXO?hQU`V7BA8 zfXI%s!2GR-OSYGpy9>jLW(?3iOn(sv_r zCN5)~)8rl&6>Hvzahxo~WOaS}%^Ss}B(lDjJCJ&1f=!B$u{VrrW>*{#}>2^_pESc4k{k2pP^ODQ1v$US4e&#y?uS6 zhtzxCY;`63-NQVOxKT;DWlmM3yqD9G9y73@j9qHvTR_R(opRD2km2@&AZux2l5|#h z5<>ad`o6>nDf%`Wq0o_baH;oWJDQcQzGzsOU=vGENZmB#k4j7cg|N& zEJ7UuuB_<;ay5t-k?*pO>`y0NhxXGY7&Kt_9K3e%<&<}}YSZgp)#^}NY@joJ)PL0X zHf0kbmwPtPz!EplFfu?q&_A}?5DF86(=I$@(ZjqYB3w5RL^4hPTr z5*VUd7Yxva_&Z2lc(Tc6kS7-0_gk2o1eT$R&l)@c8$-7ulJnu<`7ydKA>0CeM#@QJ zz+fK*VJZV)h+QjPRcHJ2fHh{bvCZj*dWvhq9lh82nQL7<#;-m&H@@cU`@L^VtDACT zX*j&w+KFm!NS#Yx45=i)9;SnPCNiVt5emqCQegm;ifkxsBVvRyAJ)DABSrueh+bAf z2%pdiX~n>B_U3fo@Us=R7m1chT-Bkh+4fN@YKUTI!yJ2i&%8yDTVT$vkEEIC?deyk z=BZF|6+Xjj$Q(=^ZTR+TV)?O0L-=w~`RBnVl;;b8uFzeU1xP7vI$MOJkIdSlfQ3|~ z>8L^6>2?5u0N4^cH-)UdpN@X^?WT4JM8_gBI!LH7sHsF6W|)B*-ePclpIb3 z88qi{@wegYP~px&!}A>sksZ2ExD zl(Xm(G@=oeEB9fz#_#3^H8KEIA^qd5=k9!-D{Svik+qQX%Y;iI^SfXlO;`jWmy<_=%n*R*f~k``%G((iZJG-@ynxW z<#UXY#h_*Ufp=c1*_piQ;jeN^I%yN632TAeKr~b46L-m7M@W6-?c^{z1*s|RXoWg5 z1lJZ$)qIr@l}y^v!?F+snmZ3J4x{cO*WkQR8>VB|#}3pLJf9ie(f^BKcY+YJamMy# zz^CEiPhtD)zvL#>-22J-)O_i|0XrMB#yEW8!u4|%=`q*ib#dP?j!OU05GGizT9+r^ z2il3W?%NyCP;GSZls!zUEil7yObxSzld{tF{>cR`F8w}c+m+gH3dA!o zrNe8mHf>Am=Czek2yLuiS{)=HhjnFr{UycAq|jN;#OC}s5%48tCUcm49bZcDw)bR) zTwXC7`u6Kz2Gh_1@{X*D+^O&dqs6zS_fc=)n+bMMv1me!ghYW=_K?Ut?2at|C@`6* za1)ZZDo#r$?iG(tK{88Og~6g!ZL(x&vS*l7Gv~vNO&|i!}&lW>?Yp$D? zSgQqXsMy;e?P%%V9KL1R)~pSdBn3Htdqv(1?v$UqUHhk+WE)gl_0IT*F4WFq82&YX zOuc`4j%x1qdi0=2ZI<-Lkb*sXplq+5c{%oFY~{=hDtn~#aEwGxPE>4C<|rZr8|=}~ z6d~X}@zFzXP(U3KSD@Gk+KKV0F{t$D;%aH2 ziV=*HT9g3nysKGAzRCE*77B>(eJ7XHNi|~c0&RqX+YzcgwQyb5_adsHLJ!P@ z)L%`I0JR1EFxKgI?ZBXYh<*#o1Wbio(*^o7CWgJNky9$ZF4I5N+;x~{=|5$0`H}OP zvTgN9OmwkT(bH$+Osn&>7^vHOb?@%Ml{rb_;&AC`^x!>&y-%cHmecs~{>%OEs4oJs@wfPRydV9Q zgO+)BkNr`gTZBj@q5NhVcn{E$Hu)J+CwUb~9~x+g7Lkn5x>zwU}_d#potO`&(4#ZYJ}_l+6zX%<6m2F1S5y&gOL^ne=L2 z_58XU?$Zhn==Zr%J~A)cJuBoBxrQz=1GuthfP1MJpXhC}s}3UkVB2DOw}_Er3)?|& zf55C2m4rkB3q!d9fH#GxCvtVQz;g3<_KmS$u@3Wov~HTnd*Krv8$B>Vjl)M;dfqLo zEe?q)dKxI+)0BgaZdmFoa2^RHHwU3{BusSo6Z<&mV>>G|N!t}pQu1xnecpG`=gObFpOR9w|Wh`b?ie5|N zK`tLiXbiX6%l@YPP^gB8%oRWbZ;)GZTqdd-e94Q{XyAj&-w@3qgouvEZU^iDt&v^+k+|ns)1<-SuLV=M( z5ut=T7DN+b?vvNdb3%_A$tWBEq4>d@WL{U(LxP2w?6ehd<1hxl2TN6twq|2RmwFj$ zAH1s)7>-?Y@fj}$l%K_xPOJE{maOuTnCULlE{lr#dKxLGWC6G6JRL)}NLB>O$)tWv zO;E1fU7-#36%hA;9JvS4s$Tg7>RpAvb-_cYcu)do3kt&IKNF9$!Q;UD<@WrIO;Y#+ zYs~6Ef`-T|Rb-BbH$MlnRKtG2d^RrrSsnEz0XVtOYUa9&<=Ik1SU34*$52O(*Nv2c z@XCfoxkHAx`+Ju`tR!$4w|{{%O2@)oh#KIC{2Zt)qfulIO1ib+E^2c$`aWF48c)G! zu`LxQfX#iCflmN@6-eifZUW1Ijy99^QrH7xRQFBcFeI^z4g{#li^>S~@+tl0x|Q}P zt4l9VbUqcjpHmi_{`93g{cOg>NYFtyNBrfSIP2nhD}J_lOhZGM-w1CU7r4Uj%w4Q| zwf~=Yn|`7|9GlJdn*d6)-*PMZ{^-ssfS$mz#u*RNY2hZ3j%xWLBRe~695%EP5v}8N zmi@Y}Z?Or1u50LzK6+|~-_kNDnip;J(U^b@^~t`1M)Fev!q?M15lb8mY(5m*cj^9A zN03s0Wv^=*KtiVwrU4k?wWcCK=fyNb*xWX2SG!b;*iUGS<-68v-aiqA*3OQ7*rA06 z=(2urt(4N?hvzP=o<*9wVOsg8=pvZfO#W^#UX0NK{Y4M&31t*H)(Z>~;Wtk~BJW~X zV_O3uJ3Y{3!V{UfFIgqVJYQFO`Oz5kHCPN@knS!tyGJw^>7b9- z_EuWD-z)IPl8pOJ`#n0^WwCclTX1E&b0haZgF6y^m4(QS#LZH83r9Q8^%TOyrkZ;^CiuDv}i<(@)divLa%?Z zOS_fNOSX5Q&jjh?jqC0K-ET$_AhkRUseUS$Y(lux_lA#r&4=BkWFM&;wDw{oc*w2! z)8vRa-ySt1arf}9G1x8EQQ&K!y0PMI48x-7KC z;uG!RMdAEENJf2gbet(?5Kr4bXA%7R&O6^WMb+?6TD8POVCER*0a63#XzfliTw*3G zwup_btue6K8;?F6Hy$a=^1tcf@Bce(;R=2K{MhTNek=KKT->m>9Gh$Y`}g&CPXDUW z0O4~;d*urhj(!(j&68cGh%SiW+lVIyDM|BI^hA{=pn`lDwy@Lagp!VyDlGqT?1o3> zP6g9lanX?*9!BG9+(da^ZxtxvM>->HtEL)%;4iU5F&Yd5CPl?b529gP31rby7gSSm zoB^l1EN{_*5hy;_hwQhenK=NvlZyfgFJ?@PV-$%7&?mdoLp)xtuc>=L332-vnD1D--(4A%l5YP$wH z$jw^w^`uB@@vLoN>q@+&SP6Apa{Y(x?oZa{U)s>GE{RgxtoFlG^|xlvOiD}9^zmbG zY8@Q#;0#gDfwRGYAGg)7LS~rsaWM{&3J21_=cs$U(W3)Iw`gI!e)Cr3kMY{_@8;dG zXZxbDM-i>k84i#dZu>s>now!y$r|to-J!N}sFhsHX@+YnE&%8^I<6gj2#MLIAX_V- z$$sVc#e=Nl*wwiOfnfUVS*dYJwlNRF1TOSmDSi!EF=$VJ5R7l-N`82KW&=X(B%uOY zV~G3nENC`l6Cn{7DJj6Lz61(7;Uxi+3WPt zg`oWRuDSl$+*!iz>blpj?`xn%9g;`@H8vNdYqEp4#MvB9vH|8s4*{GcCTM%-_IBoEV|DdiVHE*Sy{5H`EQ z`fm&+)MS>v_^4qgRFXGcn9vSHyKwHi;%%MmuYNkdV^zmBY~*@&hIZ9y7@V!xUx)qax zH0&iF5W5EMUVcLhiB{HB5axLSs&3ptvL+bk;@^dD{qV{0<@7QF`RGElCat*NJLY=x zl~J7972;*(bCLmZZ7TOF$p4Cgl7ci#JdS8EhF%4Fwj%8zQ<{3KM#B8kO)HcZ=!qV% zE-yDW9P}w2wDz?S_SV+s58?4YXUz(-l`02v(qZA-QwD9^B=toCqbjv z!lUNrc|?B^eQvU@_MkRy7rH<3c0pY^xnvq@vj@1kZRVZn$64sK@-mvSd$gQ|3;a%5 zoD|mlgoGluya$$(R9lBe!efJ~pi{~D+Ss%`N@TowBF-YDrC~lpP4j9itnE0$7znKi+CsX(Ez4 zH-u?2hNl~fn@S48nd=gL(r5SvhFc%H-41kByNSL>#zLcc!|l*Ogt4`Sw#YpLk;J(y z@o+N|EvH5lG`#{SN!HqNcICrUIF@q^Zfka>&XFsXxP_t~ON1zKX>-@5n-ll8s|z$y zSX2TEPIRmU9p2(Gk%i@~Q-5Jf0Nm2MhV|rPhStSjKmODPxmD2m++u0RXCYUk zP6*p;gSZJllAEDG23}d1r4@E3M%G6>-zZ(aYrhKzk>wT0-l#mxaVaV#YT+Pki$j4R;HL3G!p*LM$Dbcl zt;+VWBO{nU!UAO}`0{!I2Ieo0PrdhWyguDo{=q)?7&r(`4aO!g&D(r|;j`VD{`?(60KCPb- z@bYX1TjGz7?Zh*%82>A@>C4G1h<&+gTv^JB9z&!A8P)a>&4t|?M@er4fE#p@ZkTLU z?e1A19-=|DWE#?J7J}^*XMxGKGazZwqu+vMQ5GIcPGVV;MLrb~R&lw3v2l`pfsRqr zVn@Rd51!BSWsKbFffGeH&t=5N+^FWim!G_vMe~iTa#@)*Le=w!V?VB#iRlTP2#AH$_qh(EMmZZ3oy>QCJkv3Y$knAV2a}>iZ@jJjKc_@u5={Y9{_&Q z?2$y(kYD1Z5s*#9@a#p0-nppd+Sk9?T7|f~6utC&o>A+Ul2lajsbTs#f8l!0bq_aR ze|M;HO-jYT=lcK)aH1hpwBAt-P&c!1Qge~_T(R&^wOf22=+TR$kML?iBGKHe1Cs>b zNIXtcTmu{RZ~f34G$H3M-&jFDg1*2_0aFJ*g1^YHogLN8-US9izf(BTA2n?D;$7NL zFWL*K3)AQDndK+!`B9C|vw(~z(kmL_k1rcC`WkP1QPh)HKZMC{E7Li6_-21DFfSJ- zwJoG^)<^uQb`d&y)*)daTu7H>1j}s{--9S=>M<~+48(|N9TLrFAhtC~Uy5$S8lzi1 zrv0)gFT?anM|vt3k0LSJI-9!?@G~Ln9%nZZ9Ob?)?&m&@@2QVtWjA!8M{S@0@-iC#%4W+O|l z5KCTd?@-Qp)AY+%kts)(UzFobQ5W8yJt2Wc$`={OEiU8Ib5Mv3D5 zJ(`sb6U4^>Upn42kRRX{7<=tcN7?=MIj}V7;A9SjBewC^JqUDtXJ2V~BWQl*>*2mZ z+qI76jwN#oUGL|XBylB72`MWqFR24I1gYVw7pZ=y*3lJPCWRq$Tp>Os$OIgaqQ#}H z@OzxvctJZRiDUq@b>CuJ6Fr*1j`(NLNNE1|4GigX;)M^u_ASNw9+_e1u8u$0wP#PgU5h=_eQ-Q%_Y%G&o8@G%=iNS=Mw}fjx2egC z4;fJ3C0`)p1b6f8!7lkaQmX=K+ z@nw^cQlc7ItR>;f4=6%&xr2qmNiO~)UXvrI z%x`2rcz(XMGLwvx*vJUVGV<6{Q-K1ky%T z4@#G=G6f-xY6|dPbqUNXR|J4D@cWA6&!!F|4SN`Fu-0W6$zTvA{Js}Qqd!lG_Q=Sy zoyWOsN{RaBA8{rv+q~Dl^6f~c+xfh=y^1DQ);6q)Cb#QT76<(m~`seUsa z+@F1$Xg(%)^Yl?xSlVmjTr{Zhg@k$o3@q_!i^N>$z#Cht}UoCn~1Ladr zDC$1hs2EHIcF97d?-^1Z_BuZhA+(Wr%8!r+W#k%48~i&$yUxYdoD>3D%t<7AmQ9c9 zg2_P0-}UM>{v>d9@tHz*7=wl!3FN)(j(OU>%6}+~FP@vzbxsMQX z>g)Jx|596RpVxiiMY-2YCBb`wfU{E-wQ<;T$@gVP4X^iH`F4J(X$gIUc1a<*6t5-U zMe0D+YPHby2nbJUM?$UAvhNgh{MeB?In|C!ttMsw``HKL4G>#Kbbc+R-o2RWHeh)P zt7D7U7}~9$yu%9^ESSW->aR59pVjRzcXu9Qss?P!od9dy{HDN0K~wE^&p>3Wcl`PJ zhMN&fUuq7Lj8q*QI7<(hRITAb1-q7yZ-5HY`62BK!_@9`6j9fYAQBMK-9uXK812Q6 z6+t}DOrlo}$n&h}9mQzpdHwXu;~9_4K5@Em?fJXK$u+9|B4OdczT|KI?z6pvC(fqJ zVli3E(8RG{AS>%nwHu{v)GG8X6ckzfNY&b}(0xCw%qddl5s!>f6HGQqo#q76&Q=WL zN3d{g#DUAFwvg|d*w=#f!Y1=(>W2OAh^PBh2fz}!QxD6OURhSi2mMdQNLM#$-CuHb zJMnI?_T_XR%`c*OV&Jsg+5i#jnmOu!y?g{ek(aZ3@4Jm&)m}s%`~6B-<2Qe7V}6EI zOSP6Kchv`|ZB+oTjeV$JWuO{?aP+gN6dS6RN{`g*q4*BW6q9cY7~Kz7mkZHG1T7Ko zp8fe}(<|tdsGp)>u<&fQx)hykZ?~cTS$Mo=TX|cekBR+q;%}-K(c%czLAzukw zt{KCasQ!T0sqO&?8I%v+i6_8haX{%qqzP$&Y6$T_vzs}L%0j7AbF6m)OA~-}*riRA zX~f7Fse|x+!9Jq<0DHIMN8~Q)?kB<*Ec55He%`5&(Jf6n7)d-^=ux_D zlxmK9x9;sJukrEBOj+H__p@0?g2PS;w%~JSU1u5e=+9XV(`75Wpewf((%rLms{P3>;$LmrqOJrwA0x~?(%eBTdMCVPQ74i>5i zX^bO?aoZ>+>Qdu@i$~heJ- zqQ8IzV}(AX2fbZ20N>!*tU>_1G@^+;8k(f#7(=L0+KEZGdSKzcJzNY+HoQl@%|Iuu zq&+aqN*1Hnbs@7WJEEZueOmEzoKy(5k6f;Ogic zJ;f6=%u~AP_aJWLqy#HJNI=QFl+P5J02fOA(o_c(JHa0LC4#(zS{-ti6qDfEX3AXlokm_JSpA26{?(vKyw;MezTI8W4&h)ww91Nr#K&65*YR&Ff1|vzpr-2 z_Sfr=FYf7cDfEswmswxLT<(*YNBbQ-60Do!9g~5@nfBNe z$TDh!{iY%k&q9s`HDuWUXO4SKy33L3Mj69!yKm=E=iVdN%uw}lS0e1qaZ;N$I1FOL zV~kuyMi*no@@(1KUDL)pT4X@tLsm3?sbqUKSr0=F~ zV5&;n+`PpldGI#QcF=J6959|X*$y`*4=yjXQU8prB zMU$G6qecBVnq%jDJLX+_?7YfhJcGs7pC7Uz-xK)9#Mf2FqhG2tA)l3JpjaL}O=WaT z;K1Qd*=2y&0vnRI!8O>r#C;7AHXukf`B4f_QSBjgwB+vtbER8+cti~uMQ2K7SX~9c z5{U?*@gYesHs?jQ*C4~+Vz*6ARmJ$8Q`t3l>pztg@AYl-+xwy@r*VYcDd+!Go14jJ zWVoJNxKX+2hb!S&_@mCwK7I8c%Ju&+eFH|y<{H88UlO#N;TuQ?h(7(Qbu(-W=|EBn zX_MkaRm!%p4=OX_j(hAMro8oIA65lNkBvvE+HTZ*Q21Iin8_15#bNoEUku9CkebT- zBsWrIdF-LMJUW76sK;m;G@R5uz$#uhY z^o8@hRe^3?5(cudc$$}Q92oeFd38f-J9`&TWkWOr1#*v%7!cpWglmz5q4>5X z&pnYNLAyX;zDi6-@T zSY0DpyI5ZmXt>-Sw4WD++TiQ>VjChlw^MngHqr!i;l<25i-MtD!rhQg zd7_COBb&=R2%0Y9Zp0k`I+|mv`dCNG!;w20QUm*<Pe#?9`(D7ne zbR6o*XW!xOXqyb(jLvcY*50?{$Jep?oU1nc{@f}3RLiM~IZZXPHJ{lAUkz%B6NnyA zVP>H~fl7$WV3`{uB7-5YlvrG4F&)eZQr4(!e5T-AA+2%y>N|EYT|QVXLMKr~X|7zs zCVNz+gOH|!fcO=Bo>PBXo7xT19_a>#@MxTB-4SUHn%||;AWXi2;PXm_DbP8_yjP1) zV%kDr$!8F9n9vD@QdxzK2(g}!;W)tZ6eF}izIkK(mgdoQKzf+1opDI3U$1Kn`Q}xb z8r%bdP3wV9p_xQOjwUS2ZgBvcX37?Vwk%4SRjb_6ob4F~VIM#TcZg&%qxwmjp9D-g z+_d=2>MH@u%VuLwuAI83+1A?7PALpq&>nTZlzuB7>fo({l9rJBL_PT)g>_O}taV2s z6mDBb2x3wEa$@D!VJ6auBBE2E(A(nnAp!?c_#Ifiwbac%z5-v#gJFzgr1r^&4^q@+ zfl&7g)RTu0%7qo2S|`Q+?mOh#$pqDQg(vW*S{niedW(77g$H%FNrsTaGXm6Try8&{ zMDcMhjkfTI7K`ALcACxc4-AYJ<`aS3X3M#MrMPbp@&f2BO1Y|CLp;VKSwTA^mx0kH zP=zsbnqo{Ms=7k3UEy3ofHaQBRn%xR$Z^!GtQrQ(+en8S zISJ5aFm~xfH!|aLo6b+FO+sqBkWHwIpdIzfJDFsT^&@2#5>mu6G1wF-HEQ>JQ4I*% z5qvd5jRWMX-d67Vr`pDn?66-(EdfnI3ekHEXFA59xO~754xji+Tl_d5tftgarqLxN zQ=+Hx6(_WN!>Vi{uZ^0L4+BcM@e!-cFNy=T#!7ENq%Vzd_L1IV=mWk8<#(rIT5Tg9 zm2(@6J<%T^R&Tn$7c*8(K7Y&ptB9ATFam~!*$)*l(#`WS?wkCr0GnP8vgPQ$r9h7_ zo!miLIyroVd$C|RaOP`n+~KScxh9Lb=@jMQtzA%OH9=5wx#}Wh-2 zN~k~$7L)J(siw{{5+d|`rjWb9LLnj%;t8s@hjUC6=29bWEG5Za01G!+10EM4?nj0~ za~_a@-|$Sf?PvZ?=HL$L)+aK88p=r#RuJm1?8@n@u#RfRK9dDBYfn~Nv8{+Psc%*QUNep`b?mKy?a$IR|nk#$(rv$0tjF9;V{ zN1_Y2;UcVN<53=i4A>EiXZ+SD4Gha>~iTQ)*j4%yMCDUK9?!(*rx)R3o;^aM)_ zKkU^YD+T(X#A$9pSYB?9(U|u3#=XG)NGKGMO2ydFD~p?=mF1#s5{vbxmUfJ)FDK0z zL1EoWT~EIB7nxU@m~DAaln9I#h-fj#p4@N~N}NPm$vr2D&SU%Tynz)syYrs}!e!l3MCEsAy@FMS`5- z_-9ywJ`1viP*-&anS=PTu6^4UsrPfxt*B&MTw)crkPzA0fUGZ_&f@>TJ2OpzAkeqh z)U>AQk`5ty9To%Q1PhXWBp|ps5PhT-#dnb11g{nOI6j}=6mGHwxSS?(g(tJkf%)4O zjOS^GTx+0@$30cc>5F34y~=6n{{291l;atl1%8I?SHOl#Plmvw7+`Q%=tYwU5t3SB z6Z4)C5;_|46P|~XS0lG$_3I*MMy)`KC~h_vcdE1H3ufqJ&~%VSZ^UZISHh>dno-3_ zd}p2(^t;9cB=`&Z3(;>d{3O{apfpuw7MjDkvj~xPYpLxB7|}<1gYoQRC}s=9hbJeS z*a2zXt=-#qSMZ#Li-Ys_M=J^09=){vl~1DbG<;b#uW~{+-~3Hun(~oEU_law1AdA$pRtIvG2hIJbabA_4m8PQAxOW~@@%j{jL zvb)gg-M4oO79DyvV*_~~E=}GOcygqO+x8B6#h-?NM0&K&=cz|(@mi5mELuuYY=Mik zBnD#qy`b-a(qsnb9$8nl`%~x&Itk~=UE#DwC$;A2C#p=Ru427*DnEu9Z1T&q-LmH`-$Feg#=9FDr(Kf90JAn}xrX4k}KUS*Ws0{okp7TLR=hV2oLd zB;tEuxDBPn34zr1An*gthD{-V$ZqFrQtm;Ypc$G+**ZvC3sF&`%R2@UlFu2ZrQI!o zh|}Ps-35ny{lfW0WWH_jA}`x}z4}V=7;0lE$_O>~%w#Ww%PgPmW4VrDZlh|bihai9 z_6EH!cEPh5@@Ca8@ax~CjE=ie%7}Mi711{pa3NWHdb#2A)*AO5M+jB3u&}gGZO_qD zQ)>T*Z1-QJIrXn?w)M|vvDDMsw)ebU-&0iemyi1Cm(sV}Q_hPYZPSa2Hud$<3;to_ z@twDRR9Fbn+Mp4)!6reWC+yO0L2dygcMZLh6bFQPySXO-RZ@vxWhc(=bkE}N7E#K> z?ITDZi~SPe9aGUy{nsGnFTLoh-JRCqst5E-Pg z!W}3{6T{bliSH)f{i)_WSb?KoeDKL19nM^dgPQj_5mlG6H+PnV%PdwGmITZ-RMp=R zZgy1T_OaE88++NtLqt;s=md3o%KP}vKD8FaDSRhY+> zg{2(~Ft%0Ap6I<|#;Q8hvAw-l_?dZV=jn^1FZIl=t1f^>BXzCa5P#!Y4NKsD zeHGU6yUsE4xgNa?SJybD&DpAkw1WB?c2(m;EVj}Aex4|Ql#p+5@v^gC=5Kqn9uv1K z^V!-&wLWV%bEq4{rK|-v>)_7~M92RUujTlvs^8i!&)=utnwcm+o4ATq51F;oTtveT zeWp(;tSl^WwY1&Z{@VU=QEH3B)D0l%tADS;Ev6up7xY8V{v``LN2%ufC&5T&QP@hK zFT3hO@l5ZV<(2sSij|0`{7f3H^$dn_?@7Z$PptZ}4MBZEvlbev!-l%0f@Dbeu2bY* zxaBxm`dweM%7iJU%^_ezpC8V)Z3^q8ecGQj=Ks!=gFm?Hp@D{z;m%vJI)BXsYTX6B zWtTwBF=~p*9SF?E4#C#^XlfR)dzMZs%5mn*CO=@;#NagD&)A-_XcSxMc;d3#0~mE z3T>C8m9uR4fiBr^?^DaebK(b7PsT^!wH>m(!Y}jJuHL@-5&SLub6f`wAUAQ>!FJbe1p!GbXJBj zzxY;E-v3fue=@Vz=8^9sH?<%srDY+Jy2;82u?~_q6HeZ-#|zUAWBt?YxNHlcuBK=h1QeDremTFFOqP-O~L|qULZ7kH3kBO2>^O zej^SROFLx>dAsv~lcuw-x`?xue7XBJ=DP*O`Iiba zXg79i%;X;$WE_pe^w%0|xV_@k=bq0uf3oeP6v1J>j_FJc%y5qCrb87cH;~y z-RhaiD`+}I5vx#{Q%>~swdwo0u@fRiC;RqiV_tutSmi=VhT=G*z2_JNZC^TlQR+E8 z8F13|1n#UCs9A>!f!EvZQHPp^8A41d(X#-YY{Tf-Yltw0;H8u7?a~_@XoJGACc8g) zt?l|l!-*HIgM|2OC-p6PKgK_tf$tWMhSr__V^Mv|3fczud`N##)oQy_`P7a$#NAQN z1QDBd;bL&KSQi*gw?3KPzTnAH@oF>XUe`$VzRuKeA=&p&ji*tGMN_YcbFb8q&YJv8-iwX0yC9@q@|eZhCa;s9?OVlSvYeKobAd=Grb~6 zJFA-2z&Q9#e@o%5o876L5c;hk6weasxOLx#tU>K@BG=D#Da)-UmSETzXEQeYn(wi! zx@#lh{P$@$$yc+os)`xau67k0cRFl5J>YfA%35#-vzmw&;xyij{s1}y-K{3;fHEdh zA4p`3p|xj7`Tzupe8HVccosDM-`acgpeEC;U(}&(R2peTKtafM00e~WRuE-MJApt0 zEhs1v(hkTFA+3OkBqXhfAcJWcw;)7i2!jw6LYj~e8PiAuGD{+a1d%Z$K?pBo@H~C$ zJ5^_Y_ujg<>bq6^;G-@xzT%M*&E9PgStKI`87w&$A5nnkpO zgOh#NkT;0PdvV}E#8~y~SJihdkq!)p0!$Y z;i>i(C`(~W*a)?Xx;H=q5w?l*4UXTUUd#G}C7mx5!MB736tz!IGau$2pu=keI#sWV z1FFiRO3zQ*Q+Uy{R^bj#;k*G`2TSC?esco)1ul>vJqyI4S_+KcDUS&&rgqcW(s@SF z`*5c2L?!Ey#|HY~qd3fsOE1Ff zChb7#)eP&Fml_`bCQ#ORjLT8Gb^~Xb?UeKV|%dK=@qPe3=uFgukeWR87E2=j)xU8bL^ zJmJI&B1l7t`n_=5&VbNgzAFhUeEI4RoanoTE9E7^dW-+iC@*T1usJjY@GV;BNK%|5 zj!<-gqv+jm!a3Pw6KM@$C$wJSN#r4_sY#9o94%)!G^h|w-gnd#rD?VWnMfITIiXqx zm@QMzy0Q&9E#%D}=+c>6#@h!lHWY1iwjWQAK@Crp3R>Tn^^zH>!RB81=G4yZh4{94 zLm+hv3>XOL+&Su<#cQVzp(vhyvw_i{$#fi5z4?;j^m|BC#1N+mQNznZB15rGsSmM5 z5-_O@M5=c~1p@ga8TO9aKzTAp7}6qm2zFawxCxPN57L!#lCL`+yG_OIMGlE%u1QJ< zVZHbme6gaU-qI}V_?9yzlO}#QeB4JxnT4G@?ASc?xtKWP>6Xb`H(yV9*Vj*t)cVEQ zDi+Bv!UeS<;uP5-kv?~}dstH*0iBaw8Kcf|WP3nZAl&#UR8fJ0i3D6YY>I~fZc;MC z(-17Qz>qC9PDGEf9a{BbuTjdCr-$a|SSXPLns4dfGdHeZ>HPM|745L2E-`!ms`I&# zJmC6xetzf_b-Btp?C^?DxOLZjCmSA_+)?4Q=d*lR7R*pOwkQ4;eV#mLCX6#gNwesq z#j!a-hyNHr1b6C>FEU9fC)eSkK^P?<;-lk&4UlHz=*B@7 zkvEu7#y?LmWO!t9nM7K(=0H0a~Ni@Dl>QISuWCmrwpc4#)@@NkeScB)cBOd>X+YPhZ1Jpbk(yCFhM zjKT`)Zq5ZXzeLa`ZiMO-`v{>qB3d(PCx6!d>N2zIPTADz$iw_`_ z2jjf$Y=l?$&wZC){}42MEG^(hyc_=H5-Z#_i{?<$=iL#JKlh}{dX}nU&U3oGZI@>V zOXDd1Uip*^A>O12R_<0kCWT;r1Nv&gTohI+8uyiHw8E2(4@pa^W#?E?QcSa8JGq&* zVY&fGemP;q(0k`XQiMK`RA4be4@)#{i|Y;aZKqGghx5)*J<^|)dxiBg-OX(c-MEjJ z80kZ<*W}5cGBVTMduqkAF{DQTBq5E}1cW4Eh#FIrHFVf;h_F@CA{b72gQ6pnl&*?M z0)`1r*)+3L(4*UB(*^pFoAA7&T_HMvk?g$3X*p5(ALOW0V{xXNkkMq3~0~Z1hFEZ)vF}8ja?(Gb-2o=11wlbSH)5U3|NPTHM z9eF-m^=J_`tT9Gutj|ZwbHPM+h;Uie=eG5sSWv|;z{X!gF*cf^lDB|UERfY0|!hqQIh=A%-nt+j42kl?r0AZvHv*%=9 zRFRej*hj^Wi(`j?Sglaz-(n1V=jbc4(h#EVrgoR&;(cDdlVJ4hUeitaV)$)Lnnifg zN@QgKb%;4v+q2Ru-xhH;fvVAIlr=XhN9T|n()nQyW|GPRa(4&G zAu@yM+N*}Cn24}Aon}fcfm9Mja^$Ss2M)H--05AS|Bpi92=L1xWN25GPBTJVgH2RoEv^- z)ZFDmcWs4dpgiN#t*l-aVUfqc0f=lH>^RReCZCedbW3E-!C!)^f2q|}r z55HTY43kA5v>Q-TMfbC09Ip2mPHCn8KzZz0SS%+|c}ZyH)%-KP|6dK%B2--c$^O0B zU585FHx@RVSh&?S+3xB)w{j^V1dTx5^VHE7j|Jyap;7}np+Mk(^}%F3P@#JcuKv6&Tvfx)D3Iox?$r{*I+}WuG=EHMNx#0#bz=5Ft7ShEWU6Fy0{zGC} zI*jrg8A(^p3n(MkqDfMBzzEX?EXzZxG5}$v%44e%$N6ynki0-DuNWI~ZS!w%d@bGd zj?VtJoux0tYz=aav}PF=23qwb3Q@WBHW%k>>I`#VvbbW z#$llO?+2Wfz2FF&eLjq4L@im=b^M<=R{r}kZDZA@?|(Y>kEEi1JbXGA>FVV=v{1qb zD%JjkkYiQ31kWl`qtzmbPX_yBCxwp^p?bkOB&{CTZmah;oZ-}=;y;weGD)%$Fi9^+joBr*Anh$^gR91{zE7|EB8yqQ^OcxO7hud7eMWS!S6<1) z4rIE8o100@zRV2dyu3EK?Tq(unQ0$=IU+Vd?k27+@Ly*0xa!T{j&7<^RUy!EhsKBu z5zHVA_A*DQ(>z}L?5Qiz^Lq{^lFYara3eRPl4oO&bz0Og=(Z4(KnbOwWMGx9KenRu zEQc<4pJxw@^+zt&|FdTfGdDJIb=L2G5A$cbYSzrmYMZymD$mRoe3_r=Euo1NG<6w6 z4ICHDprpPCvRYU5$k|lg1599s5%T+N(2in;1#eKAfJPP~|E*3&Yt~LdNbA-6AjBJc z&i$&Z12uUheQZ$-J>8k1(fF1y)8lg+NMtk6VbYRi#01-Ad3u??x$Ytj6Jl7Q4 znUl2m3)6*74Y!IbNi$Y>;g1Gdoc%EErS;aLX7`c)~WXSD7XzLhdnBPd+9=S*L91&LLXeHyw;|H`8 zr~|fw4Fm%ySQug0Qn0&^j=S8OkU&dyjMI?2utkAEgS~BU(H?QGXC53+4YyOee3;N} z*S=*xHDMOK@URT~zRZ)m;+L~rltFaEcX%xeJfkz?QhY!~p-dNOdh^JE(4(<>_!gYE zFmVnI(!R$at%Cxp=qWrN#75#pOZO>b`V25KUgVC$HhEo6 z7D4+y&%x(b0zZ_$&HS>aem`5a3uA>x+zxvi#m`mjFS8aCjiT8NV()d3P;r%T5@3^; z#=9S?4?|W(U>kXY-~>L6D-JJ@mxUx$HtZ*y_Fjv`70izBuNfq6KQ>k-0iA}9#_7RP z+>q!*=nbfMVz<4=NaOQYjPkT2Z!Ih^k3_rRZ}VO!w#HO2r|~fZuZ{+YD{osb#mQ?y zJBQ{*ja>h-2GdPOZ2(pe8K90+8U+aj8>9&U5+ut=K>WRhF7*YFo?}e;lv*F!(y+50 z%93(LMzmxWT2F7rbauc>{^`le}_~Tv7$P2! zA>5?YgesP<%(uP5yCFzJXswyHDiV%X}|$b6XR`%DF0W75g0hgilUAuJ|u;;Xvppv-mZ8 zNqpr!BJ!2UJB3t3nmeJ`MSG~cEnOC(xM0L5qqa5J1`%vzesyEoJ0L+5Wi6D*!_~;XAO*MR>QSqzf_C<*O`TX7RJQr zn-e^3`g&~WJ#621CKaiXz1T?p^k>iT!S43a$xoOzK?;K2Jy$t~;KKmVp`gL~;w;a5 zZbA`4Y?Q;cI7Z0o+kjydimbGilH@OB@TR;+Qmk6%wpa<2P7Ie`WfZ9bhw*8U#fSw- z(cpXh$)h~%*BYq5+x);_TJ-L6lD=RWs*YIc~B6g^Uf9_gF`ry#jhTy+4*u{o{ z?4p4IaU9=&ITvXc+_{8JA?{I+W|O36BnAMX9!!ya zICuHu$3k&QM(UMrlMW-J#f$Y4tHpV{&hFxd4RL{t><;f%6^{bG5U*ikbM)Vi9I(xt zFb819&@NT6VuXgB=$3}pQ@58rL#43gC^dt$05jtB$W|zEsK$SwEw< z75O3W^wq~tf3onE$C!9JqaDoXeFM(5Jyp!x+4p>0vN?M{!?xC_Y5lzQyj;+bc`*FeYLr0_+6Btm~;)M2UUnd z;?=uDNt#4mG)zZ%Doo}fJmgw|g783+EjwIT$iFB!W|q9(sCunXz3p;pQFgrFX0^C`gVY{rVZ@1k~qAzlKA8rB56r?`~n zg57zjf}s{>{#?Mrv@sKDW*^Sy(^C5Oy`3n&WxKCWO3Cx*qLqjvmD?h0(N(l-cjZ4% z^h6Dp9p=T3#PpCnBX2P!VlBn5%0sFW@HxsG_CV%ir27b6fSrE_y15Kd{@!u3)^1}Q z-n+K1hBJ(A2C`TGX3`y|UYd}mb0IW$u!ec-mB=9<8w9#zu5W+MGc0umJH#vgl$&Yp zp1;9vf1Tnqbw_Kx!o$qzTrb}fZ+mHk>ciu8`+ZrH6U<-ujCWn^6Jf-Gutd@?sGVv) zz?VM;WZGlq3d=!$&vvlcs0yyVzpz$X?)@OwI=*uB{9ez^9XiPO;fIC`PgB@9{a=6l zAfv{<&A|7c<)cIsbrC%4z>HffsE!3-nx$N?z^VI_$1rJfu53n)sqSHKH|cS*O|BLFot&3Xe^dVe{A82d~E4~4&-~xupMH0O6cTH z*cxzyYpa$1&?AMT0R6MNoeS3d;xjV;lfVm3I}xFc2)!mt6vs(RP(~NS4GY2Y&D$@a$9-&_hWJfh=vz&IX`)N%?6;IPM?ZuT4*D+Oj7mD?Y=2{E7+Dw zkBw%!`}NT17R6$EaS!4)>QqcfTy$*3?EdenFJD!{Q3)RdT6=oOQvGHb9z2&ISTop@vsjU8}O(otn5Xq*;?yF}Hg}j=B z>5w83V4QGHcmJrbnsFOL*wxPdK+T_h9&xJu!ZdE4F+z}x zAV*iPyaDl1X5wOaYxg?BF2DjjA&--K)hj&JT?ifZA@yIpoclym=x^7C1mzWJpO^HU z`k9nJ{$)-6Sf`$3+c2n;xc$Q~S61?_H1{#*{m_rsDlbfB%Ql-NlEUQ0N9Gh!_PF%I9V?pGgC zrK^Gc9Pl}e!=F>7fF`lxjq^?x=zGiH*=Tw8mKx9k@mI>L);NB2JTG1No_qY-j#)Cg}TtAN9Xq78z zCc^uyDwjHp?0gxC0q@j(pe=5`6X{&Eq0~L0d#FV3%k=@jDg)R?9P~I6# zA{vpO>wFZjY;mX)GHwFFV~nHozJw~|=tHCn zQchCz@XlVR6DNiiXY5 z{_}vfm-Xw-JndhR_vA131RVTz_^m~|b1<>&e55|}6QOdX0xfVI<_s83rh?Ox0^1P* z0v;mz|Mo}XdvIaZ{!QMzD{ZT!7D}o>+YyLynvG3mw;qp|^hU$CKpicd_0Icen5|iY zra)JbalDXisued+upQsO*m-#q>zMG5ntFcO-l7VZcaz0C-{wxF+zdN1)BEK5N*%KA zTwH#yhJIzyz=)h(%b&07BEAzyf8r#O^c-&}Ji|$w!F)_MRBnPWieQ2*z&?Hh3j|K0 zoTRCQ$=3VHjEjZd_lFRhqdD6l1hC7r_0S4w#KsElwq-rXeHu9slS2M}I4qSHStcCu znQ`)alYnbIk(-`b*8Ydb<06_h+NP>Fq?}#J3n<&7&o1iCCVMQ_lH)2lD+Tm10c18$ z5pHU*e@odep@ByEmb#4ssNPq14zPAdgge@WNYRa`Z7d^g@-KYRCQi*f>o{fW)qWG{ z+}$>>Zvk0*GS2TYSUNG+=PG5=>RCw*^;nF3U4xsI?Jh#4@}2w>@dz4 z8>VG9{fTzDV4G8`FO7R(ZLJ+CIa4~^|Ku7Sy14ISHcv7!)7a{aT=YaT!>m_H9|dJ? z#4f~3c$?%7(E@U#qDi%Wh2yk4sI@g6l{!L6GZOY2NsFL6PSTyKRm1*}a^jNv!%Mh>F0TScSbg=gs*6*O0Mz(K473%BgK92tf4Ql=&~Gi~T;-5~&E^pvj?FSc zYjGb^p@?zPR;U-DH4<9banl$-I?vv)140hXkD$A7;FBpx-mC z;_9+!cr-eKTA^=Nze6Al8|4oR8YtxFhOjvknMbq1viJd_3C@$Wp*A`Gpg4=0?;DRy z2!0BDu}aEBl6Z=70Bp@LE~OP{=a%A*hdKsJ6|JlO%_9!(005j-8!^0J&M^A}u*nC4 zrcIONJ>faFCT3oa4<&9VkfxQW5$UDFYlm}74E<}4AG3?!l*a`fr_BI_1kEJ$x?iJ~! z$TXV*NOP@Yo|*s_ZydRT8gx7YT(j3Vt+sNLlqPn`l_fH--++*+c9nYnTEEgMUc(1JOpHoM#PY$?Td|v)Lk# z_sR<;v!=}fVWPxAZVF*l*X2Z;VYwd}_gLWuISPd&E_4JNjn*1(R}S zuS7ERRuG%hpfpz{)0~Y6LC{(m83i~ff(KwkHB;CsPpc^O2-nt81L;UMU1khYJVVH= z4WPt8cPfIQOVOT&C;oWNk$Qv;0+txdW-#8n|Cx5_3NOm}*|v(#ovp`CdELmZCQ2-B zxOa(197bnRNUc-gXHP8~GgMrQl46}`@=VB6ws%~=`42}sY2J8tJuv#1^pLs4i_+k2 zv8aS-n9)@3ivY)JO@Kk-6mLd%r}uWZj;@t?X8k31-re)dz@pLdz*@%P*wzaE_JZB} z+x#=P_jz8Z4^a6cZF|xxme7Gc(vYTZ$mAU3j#r|{i8OxIpu6QLCqlB8$ftY{IL*@d zX4H2LhG?RxRHNAmB_!sLk-i}ukbbJS&H?51r~aBa7lDsVJ9*!L(pLoA3f&!?y)c-& z@c9gu&O4tn^(<6j?&H?^*3JE5mzSrRSuse!4XukYIX;4sm`4OZpQ@@P)~|-fP-;Sy zI+mwYPgx!cABZ_Anh+$~l6i){s^1-bg|m2aA`h0ravFo}P;+CulR!n-ID#WL2gs{< z@K(}Bh;wGJ30Ki*zf?fJWKFp~*pA<~(2Nazmh|h{A*&Uqa;WmJ@}h$FoAd}H!JoS@ zaS^u)hWHIk>hwhA{B2Kxa$7t%$gYnRZpcYR(SMWWfTJx8K&gmoNpt0K5Q7RVZ;wis z8%bI=WU!nO-7l2wb*+{H83fHhpgorsIY7?`9M)r0#a&6R&T>`&-W5MZVO@hIK!W1uzSJyZf%Hm@}&%M zZ%Jj@5)e0-S86zmoU*lYIFmhcFyZ9$>8@SUn?5}Y^nI1lOCzCu-V-cj8ZT_P@-UM@ zQQCPi?BVapau2qOOxy)na4wZHd<$h)jN}1gm)aC4V9dx$?z3sQB3$8{!Zd<(CT_Q}CPg78D6aIsgvtH%^5Lh=s z+8}IQG-_CrD`0>UNf!*SYcoQflxa74CnDAYXG&^YkiFEjUgYW963cCt=qQ6pdN@Jr zRvaeKp8hFKWG5ZW6N*v(?;@>h1Y%2@x?7RdB(g(kY4N$4V)MHFHR;Sm3x7XmeeCMR zPTyM-Q3Q5+H3L2SSyG!5x?0f+dznoIItq#ySpCJ5V2-|0Aeu2~&{21SmP4x)r`co- ztIrr)L{$S{U8@t#pD*yy41XRfMR`V)$lj04EvxFE`yx8$l8PH^}2Ra0_i_|;8c?+?pVRJu1=m=C%-rtQtosonq!oa=f zfp;m8Sm?CoHgKY>DbL@ZiqXwZcy0sl@!qO`#L~pz*Ycs7y!;PORf8Y=nLM|B*%Fsw z>n+{Lx+CFPwK*8eTJ`nS&)|rX{?z>dwo?pRE+?!!PgRKl;sTt!v`L&#&m zECR5UbRat^Uv$MvkV^2xfGPsqys8S|P@ny}?Qy+rF zRZ2@$*%)-{xw;>w0qlTM#xK$2J&-^o74buISs+3Xxa6$WqHgIGQEW)@;>~ zOYUFoW1R~7w%D}d1r)n{axf;O|ChZ<9yz%byM4v`74w#(Id-gcLZ@9J>sB@M^e(&V z*WukBY#UFfTZ_o)*CDCu9?Gj0lmRFq9LQ8KCwvCkiBx}AlPereC>FtU7?10|Lx*it z>H$&Mp+*CZ-vGZ7e$Rh&A3LmuwhK+PgGQuOAvuXEwM&e#3Q=#>)Y{vUW6;^8;qpi6 z*$HYu7NKW{J^3onEe$_cDH&e#e=Iw%Y9vQ3cS1;+z~ve zWpvkM@V*7JB06{hHjbFXAm$#}=F{TE^a-i>iD0|6vkA<&*>QAtZx{8}>u%LUN2h&$ zKkw)hb9k-Y!xi>1b=&o=R>BpYViGocG*CinXmxiS8XWTDcd3RZmgle}BVap3`;HI@ z!u-g|4VJ8a*14w;Tz*~!v{)fpQNj)P^DceE(IGg<=KF*Tvtil~Xfd6KwKUEk;fbAv z=lPx5@8?ZrTbXqOi#2`m-Ty2Vzsiv0`cGgD_Dvbbv+j5!?}6^D5Xh|QN1+rAuu%ulEhiN+z4`tQhS`N6=Y}>b=sgd zjie=hNUoUX(ThhP8+5dLQOyqC@V(dTlP1PHl;jRmhfuDsiVE>IbA3$wO2BAHXAVXB z(@B~B+=OgdNJ|60(Rw(F{GO^%4F{52pgq&(#jtdQozC+hNTdnA6{mrMPJlxc9BuDu zrc!YtAeB8*+DJ>?%$`}O;G=p;lpBl!V;IQ zRM&rhg3)`z{?zx0PWPj8ilI@IJHZ;nT(}Cgd56xZs06Ic4`!@9CWFs0q-1%FEUqeV z%!BmpRBmmxw7X64JpogybmA(HrBfy@MML3YYbLdlcH?I8C% zFTV~G0mol3sbAc6E*;qO03a0RcJ@2q!+ckjfdB?LFkLzZQ2*8-B1p!>E*Wmc#>a2uQ+* zKR1(JQN@UH@^JaAoB-V@C+vUyQl@|Zh59gPgENGlVKuX}st^&XIU*!bTAWRj9R#v+ zu?Vl7v>HS!n%x>6z)7lvU+T9>3rBCH)cQolgq3~n$a8JqH`wlGwKu{lEN=Pto9v@k z2eRsEeoVFQo21#Wi{PYsMz{brwGRQTgb1sb@OP5{POl5Wf0VTf z!0;DJ(&-rg7DS?BH*nJ+^_yaILVE!c!&TaO=$AdZIuO z`LowH>Rg=;I(zeA4IS%gMmrdXVfmXrFn6GK{@3MOI$?SA#p1;g}_@YO#rrEzjpMMhW zQTO8HoTiIRpNL8`o&Ky;fBsXwmelA>vtkBi|I}y9_X{h&vG6B*XfWuOWj*> z4krq%G#Y0VTvw@}iA1RB9DHsl99+WqVQ z;4q}5X7~e=apxel9LISxy5*sKBe0c_f?fEzsuRVb)0MdN+jBwlLN8WGrJH+D2?pfc)@6!oS?q1%@=mpi@Xh<>#>RA%O#to{KS z0cOWU!=6R)`c{E9(R7AV^DSF(64Ghm>1ANCRnu5I<2ABdWtT2TENudOL+2c7;0Y4o zp;TJ2H2IwH@|(1TW39FQg&iIHNzex5G4LBdCXe5a9v(W>9yob&-T6S8VGGV6Ft3uq3$sMW@dlQ4U9`xO&`h* zodSMjVCT|7v>=bK6i@VX!7scUtBeMU%w~B8gq1DJ+Y`BAGQK=k=0CUmln=~YZb&tn z;NRf%hFY_8^q70h$JsVsu6uVlng(KoQk-c~1;qcS=G)tU#~Q$A^F{&9QG>Z0KptwY3M8m&J+BSSiD`*YOw?(i;aL42VzBXq4zeiC(hP@h$1oV0_S}8~F{1zVC^i zU9Rpuu$V{D{^@gjY02xVq8UU;h!16-;BXpM|F5k423TTVm*mp^3np=UEi0X(@mRs< z_Y;c%VKVUoLfEy$Zc8avejlZwys3IZZ>kecyt0Hr4M&_2)%!&_7DT4Ra@^l7dJ4W6J{9q<5fqF?^{6TMPbw<4n^+CO8UK@65kmH1h(8U>tjt<{d% zw|_nT{~M0c^WW9q_WyQp{&z;?|40ARJ}84L$p!jf*1U>p;jG?}j@;_`vL+gA#!=w; zT6Ouyr!r+MX=#S4&N)4;acoid_tyW%Pso4X6#QRa;+Oww*gAKhXlQ%^@ltGqfBq9C zTs_#2xqf(!&f5iNZb^7h*yXFA9UHg2DPs`j!=fIiz++K?hOF7ta5OH?+F< zWew$D6r~QJDd!}BQ{4ov+zD6v!9rzU)~MDwf_&u!JunRZ#nx*gb^qn9-UP<9j;5tA zYtnPn-{pK+W2s#OINs_z#-I&qN&!YApMp{@AtpbWfvyPrAt!{fU)HpHfG}zBFDsGf zNcytoN3sSuQBGBoKEqGFq)>MOL8*!jPLd~f_i-hjZ${>TsKoH!Jc6(7olXqQ7h)8v3AnJ zONA@A6;oRQb3?hGPE!X@)#|8;mq}7jm^w)R>y7++Bfmb8U%%R4Yvk7&`Sq~*dTM`d zf4=sSU;D_f4f)r}2F#paN5roq;@4UG>(b)u_UG#w?duxt>pt?ow%BbKQ)Sf`-@t7+ znx{g8k42f()>nAn{9R8qe(bvjBS!Lt;~$G|dT&1T>(w7UeA1g18Up^6Xz6^;;%w$c zW?*?|@ko)%I4Nw9$qM7G@`|c*knoU-g-BUU&4>LSkR&y!`anZ`yDm-oIsr+j-j*~4SlVptB*AU`w= zqm~(($Ke}L49;?)=(gOUps~k;1ww6%lja0_6iuZD502cxwh+TjHi;WW?UEQK&wi{R z&_17X`devteB|{YBUz3sd7*oaBSFVznKtx}9CQ9Q5-!G{Q+SoJUA9#qKS71*b6p_T zzfyM0ws9m-HKOdA?>WTbs*PASryD#373=!zz`d+N9c}Zrcg2yQ7gsY!g(#e_AbOc`}**M>L zVVLONC|k1ywTEe23BXo^HmhbREeL&=I4!M3;61{b7Qr_-mO_xLXSA{<8nts%VsGvm zaYD~EUlxC2m~_&m<(lgbdfQDqIsW)$lrR+ub?9Yot%{YKE&kdStgp$8DqZ{|CP!P8 zN21#fr8cBePv4HFk4D{Yn6Kc$a9h6nlZV|bB5E_KKjNP*(a#ytX|D!TD{ur z|FVeqaCK{s0IFfL*Rn9zd+lZxj_F%Z-iKu?O{UtDex6qOu06yS_nG>5Xhn;c+g_-h0Dpv$;gr3IaSW4&vTj2cBwd{; z`U5|{*H)$O&Zl2M>w7p{9w!*|sWZf3cfEYq4)-Als?u&NBbf8vZ*E-v>)xVhck-MQR(xgbuK+&sdyC2|mH;?CIcg&x6y!nd$o= zKgW?VcQ$phzVBiUabUoYd(Q;o>LSj_i2tHLe!kzQxrg0vWG%DCbkP5PS*d6R263d+v#nR`AZ^+SO@xnG-TIOnoW` z5ouqnR6m2+b=9V8Qys{wMn1w!WlcM46*jUx|IWW@)=~cHhecKPU6DX*NA2^UQCzqbn_p z{9<%3mD=6ncq7%GH!H-lzuEe66n$^_pu5Ha4Q3+;y@r+e$aH&KBo49+u7w<7Bf3-;d%OOoneGsMNzX(3 zQhUFH%+Mi1G}m+X%{a&>+)>8%bkt44$gSt)ziFCj+ zk`E$AtCNI;kzo^8tBCdkA%1>yTG|6Cvm12D2U%EBretJ6b|+Qe^B+h)M~@z1Bw3w1 zkdj(FmMXL8WK-6s3)(?ONT%<8uxED_I*1Y+IsQTqxDX!HCf+NRUJqy~H<>>GcEdvx zAg%jOr$#!~-e&BS#o*GiELxWE21# zjxf@^7%@B0`nErkpu9Die<7X||77-E?xY71~xghY5(^2?T5=XRKiD2hyxvp@4j(R=3otpGGP1DP(a*@EF3 z?0D_^r}h$z1h#pqRo!WPZ9pG#fhx)0q1>vM(X!zdVbclbi4mp;h}y|9M0PC=tE z{tC`3?Cc@9omolQ z@oP6fIFvYBp!_gqEY|31mU80DvIZMucCfjf)K+Gk*D};i0^vzUUnR| zwtQV*XdY|8lH%>=GQVB^xM62ik)zUMwtRZpRS@AKy}kf-%yiz{U0ycL&5X_O)0#8R zPIe2Lpi0utkwMt8-OiJmB3BI!N_HFPulO__Yj8G@$Udgp@Y4R&2T4vARPfZYbl9e@ zO}j_mr8gXX%?nAh3RYQrft%2!{>Lc)cYYoLZ=99QW40xe*Y9)yU5^>Y(_Zar?M>@nKeJcNiVDrW+eL07BRb)Q zz5~1fyyVnx=GQig)a6`- zp!uYc7u;aUM6jSUs#(=(+D4w2L|o@zAuJDr5^6(0r|J~TlAXKW z4BErr3oH8XqMQ1{tnXw&ur zx>b0+!O)v?8-ozDG-_&|l2~fMrLJU4cB+>Q?OkNNokzh)UewN2!>A&%)ki%YwfxNy zmPK-JKqzj1;4VOyg@J5{V7<<}m;$|~p{y_k_F}!hR#OBu zc?id+`W)v~iUz!e-+I8g=BjP0swGZ~+Y{yK7TXF8g&X)wUv%v&>F??k;3#Q4>$qI! z-ZUA)`O^eOR+>twoGT9nu&cd1e5?mABj!C|Y9RVzgE0yXL@n~ zD5aTmJUL_!7s4*`(pXhKNxsEUx-l-#z(dTEHP$7HSv)U>U$93PRK&i%sM=X&CmGOK z9CePkx#7S|<;oLtUMKEvIx)7H_?8qF{zFk(l0jP4D>j^(WP+>}@O*uXI8Y&F%<4s#L!X-8<}Cnlv1rdw_5A znAoyRmwqbiutGl~o#;GnuL^L?u6JfNIQ`Z-p(Y>0wl(d$yhnlW z@bF%Yi}PN3yEZV#@cdSq#NkNm8SMkemABhrl9j&MXRT8kslGEEYs5$#CBC;w?%3ND zJD`)ApXRJPi|_r7CaB{HARChG(n-U^Me=G{RIoZyQ z#31}41`73K^*i|CcZb>?_!`{DUELR-YQKFzne1)NLO5av%!)ED)zcD2o>~)O?!K-Y z;I_R^Z~FcyRfo@Eeg2NdilobL2d=8uUon#R#KV^mN=_T$sL%Vbqya;^QViGETx`jM zI_l4k{-wLBRDJmPD$k+trI+jO^&HA+l##>=E_8%IZ^#st;eXrmkX?20iq;_JYImH|}2E z7_ux5R_0%dpusp;Ob;neVi35T61Nfi%J4A3@to%Bn@3OWqFM|Ufl1Rg^mMJ=E{2y% z&+aDs?`=(fn0Tx$Q}^W|2{O5Z*J{o_gp;VzBGExD+d8`8*;6_%W<#H^nQIp zJ^F;5U5T|0bv)|T6oKt0Nqo(c1lY6`e}fO^tqW^=SfnY+bwJTg9nvj{ap5TI_>{ZA zPKh^?DZWcvRZ~&zZGjIcu)#w{reXcaxs32Dr-`z}i~Vt(NTcHZi&6@rhE3Hx#SMBI zzb(Oy{KLGLYb2u>)Oqr0wUT&;5N?S#9D%{RHQSYZU9QYR@n*$o$yKZQR!Hqi_26s& zhCVa}33pemV0Ma^UQ^aX>{D8|-?qHf-dy?ob{2;s2hx{PHlN;=@5xgCiM&~EllcMH`rejChTa_rqKz2{t_s!a&yyOq`NkpO0M3c=X98*Z;7tluAU-49EwY=~dk#}}xBl*S*{EY-7a zj0yVYOb0QMhA{Esg2(85zP&o{H_?O#c_HHbkX@1Zn40kJM^0M0=F_$OL*dP2K|5Qs zsmLcZ4s8Wl?$*f<9f!Qz_LlI0TjRu2*{7r-W{K2`7!dM=if@dHqJ2gnQ2V<+E8p-F zBslm6a%Z{wbB5e4Xh*OUzdf2FDCzoiNYzY&ZF{P_GW@oZ|5-h;_2+?VWBS(})KANF z%|qlihJc=3-oxrAN===X+#!>@=;?yTE-}aQr|+CSUpMz*%@hQe>|T#d4o9}O#q3^x zzs>i`BA_Lm{weu?Z~xxefjBzevoZ6y3=5>~%X{g`UKpJ!`jgAz;H4;vGqVY{MH*=N zUc4Qf_{gnbU}QH@0l$0UFp-_%w{l(DAf*q_pRLVhr(X3)u0Yw1RN9YvFB_DMmbMSL z1?eSYK%CrkHu`flNWs10IH{>Sa(FsrC5^o4oC9Qa*ETV8do%;i3+y;sqO`?1v-e&pTx&yN6k( zDpU33yRBTMiFz|phpT1R(z9-QVfiA9L-!t^t~DRZ4KwC0lj;hW*EckDN4dgby>j%i z+eyf9aS>99&378;Oi~$^{4~;0lLfC+(iV`#(sr(Jdm{T}@s6z#jl+>)(<70x6hR#d zI~XWhGHjxt(y#GSD%s!*AasUaQoM+mJnB5i$!R3vvh@QaFnASUlimnb9z zutCwzRk{>Gb~)F~niAFQXbF}aQIkbOQb3VT9A`Wm#JYN z@yj(BF<75;p1FjPts~B0V3@9DYT~@?uw9ula(khOODFNjZg z40EsvXldR+wWOc;-Hs%(kZqx$h$g){c$hV)v5*`}x4{&F0J=F`^ppx(udsGi0VqSnxq>m91$*R>Wh%RlI(;(S zz+2O+LtgvhY_EVLZ5C0HbuCo(UF3_k0WwN`%z&qviix zXg@uYMumJYLRDNCk2(6#U|IUDp`h_G)HT^DP?LM5ACN|RdzU5Rg-Wz0O8m#2Et&I? z)58gR45cMNQ?kBmN{a7BJdYXFfL%~am~94<-N8tQYelQrf1nFz~0%~6NyuP=k29>p9Zy+~H5$N9W$ zW)m46CSb3py-+hVynu`|4bLA)DSo9Gd%0a(V4-3@uNR;|JpI@$nVR%=iS;_Whv99F zH>+O)Plw_S3_{~F#D6>9(zGWHr554+Qj4&p0(4v2c5`aTc={Bp%f+Hp67!S*$_(4 zb|a68rt?)z1D;rRH|AH9#Ps#CYrED8z!vPFtU?1?rf7fru;@A@vAh0x(CqV}+^4@0 zu4KrC1#O^4X2n^For`M~iu(`^W@-06s&E@QUWW^Q1A$ABE$^WjIp=?Q{x6T_nH~QB3Mdy_eNc|qm_yvpuGh&`ODQOvJtqF5d`tR+@@s11l zaDVphywudsh;jau7l_Z30^;yV2N738k^b}eunKYdKlOE_Qi1 z&rrjch%wc3mQcaVtWpZR$v56^9{xz0-<@)tWXA0F~%&uvK=%u3i z?cu()P&%}kXIf4V@oBMd#)~DhlcWTGBd@w@eN3sRU9*v`PeOqyO?NSFI$Tq z80@pWj9Bc~HYzmUZRc)KlW=&Sj&o(1_;5y5EMaY|(94g9J&5!NwUkfFvsP6Z&?1f* z6~`NG9pivecB1a2cl$~{rac6VAyGzOKuZ|b;jC$M?VSK&+>$y|Y7m8%PQBiZvo;D3 zrCV)uKiBVxkXs~a)#pvb8u{tkSG@5b^-^bMpUxZ#Cgzsdo(n9o=}zG%)$fRFDk9sO zcuGF`>M8xRVqT(WO?}p%8F@D6^K<*PJTLxm_0+|Jx{phwVGTe?oL9<&Ei1ELG!)ma z+SpYOz3Y>v^X)t1IC$^rxdMdk@+&~#ebx5ynMDbjOgyII60+#;0$2lE0KE~~UO*OW z;l0oa&j1XM4TmzJ?O1iO5bw#Pf-WcsxNjv2*rzKm4D_uTK0vAj==y~c zwPTFXF$dUrejArOOUECith}av$rWNHyl-3ih>?_m7q!dc3!mI($0WbJlb+ldS#B9I zDnVA;76*3qqeB~x(S?)c)l5L?ycMM`}u&rSCABcx|aXDlvh{Vi$lp(6)>bM5hh>W z9dbl##=X!tx08^QI6G7pfbz+d&*}%IqhR68b48MwKK4B!kp-##}xS_xJHacH;E?(SsQQs7wDYHCH zGlg09mlWr!-u%?(T(`PP;(7QL(=D+Jt-J~~20pzN zl*QR=qDzArYvZ^Mk^*GcBA{ANNnZuhQfFBGYMBytBk&Wh(B*5XnV9fo$*LxmtrzK^ zDU<14=%|nBI;!SQ-f*xiEcL$HT~G7Q8*PE4qmtp0dxOE*U8CHfU!Vq~x6bpsCi{MA_O3q*?G1>Eg-C|+0zlcPm>Mq7u`)Bt9A|B+r`RuYiflrjn&A(!fBmi z`m60#NMr`!P*XQz89zY3mFyt|xaJeLcbrvW*V{Rg=V_H52Fn}sbP6mb3uYM9xLGT( z_cOmoGC#Qcxe_H1IQdDDyG>V1iDC6;Amw~9Y+tIyhhMsxVCib3Dl7n9#}npXi&+}f zv3m7bt$&7H;h`eE@4BPsx0TP`5&(f=#aL7l&dD2Fes~nInyh8&txh7t@(Kn5{A<{V-|%?PWxnsKrv0mQ<~huK zJ}&r9MrwG8DT2#AM{%yC=WZDrndgs~On>eZ8+y9BYc|#YQsto2?ab<%$FvPRJ@LfT z&C8xx1&SagmO+a|lS4TfaUCcKC>e1GG>uJm$KztSho1T=8G%ZO9N?-9 zfB3}y&3ZGE0UcBHYCpwnyk&}=dLE+lnB4{Lx^<_#;U`xTw)>}&KEFOC!-9yJ!kX+W z<=-a@h`bDK5M(k%NKgXDa{`FFrzWGM%+7`?l@&JZc{$F~;^K4@3e4cXTQQ8Nw)obz=dC9qE5;Nq z1Su6w)MM#_a3i*prW<_b72A~9?s1ajYT}| zg%9&NN`J!!cjj(r-_5lQ^j{+}(5Zh@E@gI!-*+D-Mk*KYywZUZr1&+zIWMu3uF-9c z_obcv+UE-DP?e&S?*d7$>Zltfhg~L%FSzeM>d1QQY)}%#NWn=NL!VZ2$NAjs%zD%h zBO42E*xQbq8-aZ8n;rj=^y@=wk|+WWuNi2Me{+v7rdUL??jphi=~^O>^Yi>pC2XUt z@&Z~`kdi^;wwP9|-_*Rvw*YS@&}So{Kb&^YzPYGVn4*D`qFdEFSqtefjb<7 znxXaAB4T7!Njjgup~t&ip^2*6DOEJ-Nh@qi?7rycW--&R^tfMx6V&Cm5pd z4t+q2S(ll4AHXl{4h_hz1g=+IyY2{IxpiIlwF8+pR36#d!^*F_P7B@mb|W{e)6d8j+uG+b#<1F2up!`C~RWhZaxBLZ4% zi{5gD3vX=3uTczNJy&VF2+Sqr?{)bmvG1iBx9YRUqWb-d>*rVTy?VpydHwb^W8pkD zeRDRbvb-C>A+;vP{-yZt@1w@=3Ct_9-{Cwu4K)ckru?}?cmE;t*k`jTw8>Ea&Bs)* zui2^bP)Q@X2s-vgJ=?+yt;yCZix1m}{RpENnt%$$yQH*|{Ec(sDBUV+hv zaW|$ym)CipG<}<(nno25_hz<7tpE;?F}{pTzf|OY=_ktsRGmBQR@vJb1$DiJ1c5^R z*^?dujl4N%S<%RS2t5vk_ev4v=K@+xq-|MKeQqv7mwS@9HO>~@Ep0E&eJC+>h*ZqD zVbHc%Ji`~eF_e|m(DW$M0`Kh!^qk6C=lwu&mDS>NUDO+sO&%&4o{2h;K-ifK;pWYM zT$HpR;8cmPMpyyKHT7dQ(O(8OF^FeCj`eINUBs(=l%{%cDYJgXO#lxjQJ^kpu*8%% z-@5(+2(E7`B?=VU=;k5E>)^rIrMenDd!A*}Rjzu`r9vCib2fwaQ1LeH1`dsAR6A9W z-3dgvN&Ss75wfj!hfg=tc`qfKtD><#L1bR#?cO(KUC-9K6rnb@rFqt+XTKE;9$~b6 zTrK?HyYqKR?D+h_hU+Pr`X2^3eLNkc{-{GZE3LYmqZqV7H5$Gm$Y*jz&SW}9yRBcd z5cQCRE0niOEML#N=n0UL&t{|?6Y;amp(xEEI?t*1I&YK{`KC+y2S&0CJDs(TF-Fr2 zo3!7UzSO`c2;FrXX|8fdgh9ut6SKtJ=u7pJTn8@X+K^Cm0xQtJpzttYxen(iw$sDp zI50G;h2ru^;_irhqy#s#ta~`CwYX#T0lO00u#;(`{(e`}yYK=zs|trsG^*pf>_DB! zMZu-9xw3I0-BpbS>xOu1qME%YG)O?u$*b$peNlc`TV_HIT+#f@KAL@;i-0ef8G>IX z+X7r=(~|e1W*^N9$kFOW2EbXI!P_uzoo|?05VgJ!bm!7hFL4H?k}Gqj5umW9CRJdx z45<=m+8D&T7Oq}`?AJC7Qb`uk1aAR~UAy@iYjPB{!2|}b4hPA|EEDzdUCF&oCd#jG zJjVC(Xu~d%c`g(}o8CXYsD=Kd;N*kz#o&#H?raIQIz#DXrw<_NdG3c4ngS@#CO|cc zn?jz(S1lB4@S3+#^_n(mvQn4XUjjn6N6cZn5Qvl=m!UiA@8 zxXEx`*U@FS!Tww{t7`7oI~|J%%hWnXPp-^iL+@Sm92`=n@$oYIk<|Mi9CK|H4VcMv zZSElV)9v;czidS+K)|%OH3c%$ipT`pV(zKLvgP^wq9D%7^Uuq;tvOiCwtggBT1B;* z!a?KnT>XwhWC3HWMSg_TR5TM^2!*y1bbFcyb}_aMYTo{G1;ED7qiUX=n=AA(%N5wy zMUayLEzD^Zi%#v?^)uyZ=1WjAX(#>z`L-Sv)|ApJX!zc=`qe z{p8cHl4jw&4U)_a2pA}aI@{WoLjwAD#}{%3?<}$vEjM7?II6xpq<9*X>c1zvS1nWB zP%+gwRp)~*aL~;E02jh@s`lt{d{wQ&8ih#9cP(uO9b&r}gy{&%O{wmo-D;ASexddj zTi99$Zw^Em@pCT#)mJbr4WrUF>*D?ag*qE69vpXzVT(OwCx??jP4SpJE*uUD z@#y@fdaJf(^li~rL?;KuqSEfYLcP@AJM;9Sm&dE9cwg>@bsvtmX0!3I$8KCTi@`!) zr_}KbJ(wr6VV-D`AG$8K?qR(00hWAZu6V~&vN`MiObk3!up)ar}vZ3fx+Zc$T9 zGhBaLX`(gR;m)l&0`iclLeo>^`2z6yDq!I`D=(hI+ts|SZpr1OLG##TwSLO7YSUK_ z>}wv2W+iaz_kp4@P?t8*D?-lIUg5hr@d%I4@Ok^r{$wcUcQvQ>W>|eht{To>RK-^8 z+aErK<(- zkNJJP8AY+rM9!j4Q^Bgh&cii;?%i5a5-^wwxDiOx2(*u+<}=xQl*BQBZ~1sy1`u{O9P}W8>InEMJgZzVTxKZ-I9FlY z=$ONDVbsZG+(xEO$+IcmS_K2P{i`t>Q54641&j9h5^&6PPK*OcLM*p0W^aX+avP1RQKq#flXV8>RVXn2SuZmTs+C^q@pXI1(K+f|jNFQ~!0xQImV9c<&$^nd zTLwzod2f{7DA}A0iG}(CB5egv;&0P9gaXVUT2>U7TprMZuM_}%8lfgninP2zwzc{B zm|J0=A7J@lAlxnlb>|GkiL@?X_DXth(O7(tC6PP3w{@lLETYO0d7XXT;PwK89thP~ zF!it$@7Q7vot8`Xh5zR(nZ+bn+>QTnT56}!e@3FJmt^?T(GZ`+o zM(@r!h2yptiW~6-z-7yT7Y{xqI3HV9oYl;Hr5=0|Unkh6E$p{3G;1T0sfVk_E|F&^ z`IuB}*ab?NX?@sF1lL0bsK8TcV)ws1sG3|=O!r)y$+gt?PDW4eVqn=t#StHXEdA>? z^wyUfJd?TZVNsP~A>4F^)}h6`uPUdji*D!IYhC2ak}@l;9swxf<)ewOy-XSSW{eB$ z7hVHnY?ed=sTC%boXjzUzK1d^VI%Y*Y(mSF`lP{t-FjuL?CU-Q=)^UF4TzlSNtpqQ zm=QGzLz(C8`;)EaYNHf{Zql9POzfK1^o%r@tG;Z7XIN< zZ*~eb#fW`_dh4ttpwf{b`pKk*-Uf+%e^F{vhSi@%12Mk7=laim4?`DjjPQGqVRD#G zM*yn7{0k?E4CPd>{NIO|KRYY`ATeL)07KT8HZ&pPwn!#8e&3*={8R8yR=S@*FiUf9 z=c)0$ZF*OJZk1dF#bhD0c|b#JJXL@!{+yBb7}^okDrHg&8ue~sV6q@qVRwz7#k%d- z2Zpg%#7r84uvNZ}(9-k-SS^0<4jqG`+(&g;pO{7nvyloyK~LdHUPo5dl(Tj4 zCH3s*_WcX_UpIfy*aqslp8mOqUGSA7a3gPF*TIVKayi17-(bQIuH?n{9@&+CotgHh z>6g3W+a4)*ky6fVufLpFW`OziemI*enE<;MvQWF@XgOnmId7XtTNuY(k6Feqn! zt757lzSTsP0$OtPvTdBZkbpr3c>?|Qg$CXEH|9me%fDx09MHC+&Vxgads`o!lhyJo znNNBSyx}zo;XIZp(ok}gQE|nPdHKDXV!v-@Yw!cWhp`~*aeJGCZZ)*j%mi-8FnANo zE>^QP`60GdA-NSR;V@crbm5bm#7@s{320hLANxS7o~(9-EdJ!}VE5Pak6+A>Tq4ue z6kr5R?7|C)kcO~bjN}zSF_&<(-N)at+i5-Sm*&57y=fP5T4Cy(mfp_;@0K+muH6#Llx>)P5SdC z_BKuNH6q2s7kMo@g2+`xE*Diz=Gpi*2{7Ml(TBX{0r6xap3u|C7Oa$-0+5EXoeN$! zkk87J|0vvNbwvYXsB|Y6R0)o%XRCxACKY=v_C>p+;&mbFlX>+ z!hKP|EW%@Ni^`&sq9%IBK;k}5()2OKOK!;u4PZ&$G;gE8(%*ZDXL2p~R$%mwAU!L0 z_FQoU3Y3LJh-1!2d07FVrm=6JHgLvq7dS;)_d$v6jj=0w(3+}%e^APu|WcIwG~(F`V&Z$6Ta$ga(F+KLYV!Bd0!GzWb9mTW|c zVX7yB^8lOv_7n2)4H1276HwjNQ^GvpCWaCjHzCy}0T6r5l=PuE; zBns{M3m{mH_e_G!e(%PDx4{kG?Bek>dvUc$QSIuy#`~5=H+;I_cWYbKY7;3>FjxM$ z`?tEY(=YW&L*Lgd-u2@iiV^+J*D65SzTn9$|I;T7bq>3;O!ROyYdNy$?vuFp@oA+vAe30*n%Ac|8MV~ z+U$%Bdo6I9Huyg6x=T?ySqoCY7BB}TM0oT0po?w;!uafo*<0!zD3^b9E27cB9T80& zjX2xtUKq!zdkOs|kTi%BI?A{Q8aJt&=Q}`wQT)06q*DWk$nd?Fr;G*Lvo@D%{9)Ot ze$=TxtMWcOt&OW>N@p$PwW=4M6WhAY^<1iUU#3*#uIuBdX$~g$2Q|L&3%eXF$_eM9 zufuoS{r#?<&fu)Jg3aBgyKYb}W~{f8l&}$PJf&^q8*_md`JDKWZHdHp=_vC{K?P#b`z?erF0dC*_w?ub+W*H?!bNnGu8Nzgi~jaj+q_7 z+2{63Cr>dJAJ*bKViwRU(U?`xV#a~PCV^5!X8-&`y^7!_N`1aHNXc*GTavq9RncCj z9uq-q5aBm5>BXf|_|}oQZ+DcoCPOwE*SLx6R9klx$6N8$JCwME$r6tl+Qm4}V^pA( zaP@(Isa{doKG;Zxo)>`ENc{BKsc;|3m7iZ|OiDo(lq5}GJ93b%!j$nb&Q)YwVk<*W!AK6>$auxLUuJLw%I~G04OJ79;sv6x>;*-ZlI^4%om_e6zbok54{j^^F z@W}y&Y+w+@)3sv<@vq`||H?|sX}`aA*YDF;rvV0urSqs!K7f<ZX<^b-vrq4%fWPg)0oP>P`L#`|jkbmRcIGL02<32nU2$UF!*O^XF=!p5h= z5a>QqA3x_pO7$#R(4xGYqW(b!;RY~yG4t5C!vQub4fw~P{0hLnJKBE?%3q!9KL+Km z{@@>j^3$OG>F)k9DF4Ajc}2bRAP@4H9J(alYH%Q%AA5qMW-!U1dUwO&E<uIuiEj)nSa#eA2s<$P5uBa|HZ*SPUjCJ^2fpd3u__;JK_g6 zYKt>|NGziDtm0qcrWDH;h*CD#Z4MdoKx%5!i5Ye5?{NOyD?%nYU;0#kUXl83HzgnJ z7=~vXOTS7}?lre$B@pn07@~rXKvXWfVK426FkT!=PpQL(9}^uS)mghAlS@(76ER*-4D#F`3FaFFu0}T9iEeuQxRJMrxz~ zM(Q(`(AI60i|XqOH0sLy*6WEblcd_BTokq2?}MtgjOby3-2Qaj^%z&5o#~wO(cH#UsjpOxOQ(P%jJp-Q&bk2Acb|YTO;AmE|&t#luf_$^^`LF1~o%=3*WuEqhs=mCFHJfwM6DzWm zPj)0o9@G45_$F0%gr$QnPva}3lh1#iXB*#gd7Z+b?^qfq<$Xl0JF-j_ zF1W2aR6kC;3P-Xc!ZG4EDq+`Sl*Q$`#{ECJc~`oN()){uJ@H#N54|vU?opDBI~lM>_l)Mopfeeh?GuP*C?dSe9g;3V z-q>+CEBHbdXu`V@J1WVy@pe&D{6;u8Ys~IkBw_As3okUDyHekNhHhx@X2wxQlCyq) zAJ8W=g7z{*6E-z$@rC`+@qqCw*V@Z{O`CH^2Fe2ArVEz8d5h^67kWNBEwRn^#Bay^ zHJ{Cin<^5XMwePo=6V?<;bG*^nukTo zy}UT#h?8 z^pTH^=&HJazn(NrYoEv(cPtHT~W5jbv!dDMKfOvSLj?35-S`)X&<@?^!Ok0u>+^f%9!UQmX{1BzbY z=}qZhzSio^J2=9J>Z8Q2h}sn=ypGg5tI+SVB);a-_eBSu;raHB)iiYZ@WN#7Swi%= zxGUJbZ$_+K{-q=@!v5BU!(E$(&O_ zaXsAydcPe_A1rDv&Ml$Uq-ZEBUoo*#5|>%Ev=T9|7OQZaET`ce0Y3eWfj340DtuiV+*p9}z@^2WulXg+Phv z(>a9yYMj-FKHTe9H9#%gpiJrFzxZfAHRF!BWn>6ggjnf@P~x%%_1Q$rCv$>d8)=8l z=4qW;Kc>vxrqyDRN?RdRO)a;JSh%dlP`WbvnDf_V{qG?*{*D6-x&K&rXi|dXE|u>% zK5v9w$WD1ZWKl<#=vZ!>9%Wg>)^fuCTdy|HdImR|bjYwug^QbPsP&7$FMsJrDwZVl zyfE81&9>~g;uPLQ#1knEy%I?F!j3pDDns0INZH95dOQL$1XDyw@A`)~Lvq6PL8T{C zR^BgD@*l*Azs)wnVqYP~dTO5P)tk=5WL9zSUPPmxd0HkF=& zzb?0bJCnolZAa7ymcxV4HnakNEAte2oJTsbY2*+qL<_gJe6rgxLXt1hGTok#T$S&} zjIiv;3GJ)sQFdw5^_=Ale_X3+Ix%a`|8(z<-)S2~gkD~#HRk+iE$JV8J+Ne3UAd1d$lJD;Dl>*zx%Gg=)zu8=bBA-u&D0c8qR~04|#uNp1*RK1?ygW^RO?nM^y(>nq6)UZ z>aHVThrF>Xnt#7vpa!{z2#N89<79Kx0hikeeGDULMMGeLI6cV}Nx z1ufo%=>M`aM4I<;AKdQgl}Ufe4w|wlMp_aXm6F}vG1KhwhXesyN1qtg>gAhPs{`J1 z$%U`{@xM*&Uz9a8n~+ck`8A+IU;Jj8*t=QuV97_VrJ?a*@b@v<2l%ItGS)PYY5fA; z=DY%CjrJHIkEG1t^dy`NJ-R?<$(QX#|B%@KbRZRRhV0!u&r=0ym~_A@K`Pu7M(Xs| z(i?0qZC9)Ve*vDA+Fkz_f;4Rb7{Hpn^Hzrfy6~&O&T-@yN&F|{0OqZ_?g4=oR8odo zh>qmNvCUdKQMWhk;v-a1FD+f^fMzf7s&0imAI4WX(zeXkAi(Nvy*b>yk6tq{p{4vEYMSpvaH?!0FVsH2bwZa8 ztZ&@-zc;-X>~8&0Hpef>z>`GNcjjMT)bz<0rGGM`u{E)~TPaORD>+OY%h@9p0QQBw&QpEsGR~&;Q@f<}ZElK_jqF=cYEV8}a?vfv!*gB|`G> z20XS6Hhji5c&r$&vVRZoLpuOZPrK(ogGqtG4NA&L_NYA3cMzaj?(})7gnXyaRU@8BTMr_Yr{_rfq z1fYiV$POtw4yes}RP}I`p-Rgt;N~Mt86xg$B`F2 zwaeX|3hE7Rj{FT!WzRnfs~C$Re60z8z{DMXJ}4DLKGIV`~cMzvUb!I7FdI&svM02T%&m0 zj`1tsRm;^I25Ct=AHW}TN>QGBX;om4#3GGA!IeZ z#TGC8k7DM(e=PC*CzlM$rb6gf?bj*As|G5I(7(WM;iVRI_VJ>4Y(d`M$JFL za5sNmT{|Mh_Jk4;=2dL;Vp5TMaucR(Y3Vb@ zKY+7Ww={~6gTv<8gZ}7^kAA)Fv;df~&JGecPn6Z0e?+tY-pGU4=C;s$fi@TIu{=!z zp`x+{!AB!F=XZ0?J}~Ntf5;rVvYX;oF+b@mC(4<`PN$i8mv*e;KjREgZA*Z-8|Wjf z_ox-@9Ih{QPLJGLMgrF(3vUF2+h#YHJDd;jyet9CtVpY=JIzAbc)xJ;8L(8)#1Sj~ znO})bT#D=g`_gPG>t9UfL#7r2W=c94A&PqoL4@Yhaw(mt78mWduW zu~;y&e$@L`U~6ps@u@mAzx$L?2zI+)lH-K)tS3M7B!&Lt|LTGoZw{g`X5we9EJW|$ zKbDCXNfWCr>r_sMt#0<$56vuvSNqXS zLLk%TtFh<0pPLHq67g&wd$aRd`XDXE*u9qf^QKPjvk3X(gJyG;_V1t@BEapintpB^ zv0YL8%;rq;747&}2@zXm!CW~sCX$x$sxkUap z4seS?MJs z$>Ov2Y6`*AsC)u>E9x!49`SN}{O;F*+)!|se%8sb^qGFxTXO>UzwYrjr=J|q0NI>o z1()Sw=`GlldVJdA@lCaT|6sit?|1uKHnLr%af5aw&yp{clgzVu4qs*UyK45Zf?X2a zzo9rl6Fb#wf4C^Sweo6Y!}ESipP`&3tT6<64XS?wRKK=Gu^pHafZb8$0elU805-sQ z&USLT@Guu;Lyh_3J;vzh{`%E@nwCGpVF0q`QPpqo5?b}bR_J>;4Pdvj06eRSP3Q*0 z)&btTzT^`C2iWjL&L=0MnHbJOo571AUQrA{s#UGrm+cXu*JCM@P}I-I-VECs{1yCT zWf;?Lu9k#UJGys)bI&vGK3!A|n)Owd^R`;mk((?EN3YLaP@-vN^264+$~h6}MAYjsY`$+7&sIf1g?)^Fr%-_&!YI6xm(=75lpz}x)6^Y)zfwFzJcU-kH ztM0{ikW++yLpk0FwDU?mHtDM1mYBdPFO+;OvJdBuJtV`nI;=Z0)-ywDj z=R^m%`y~{05v6>RcwwgB0TcKtF0Z;Dj&{4AtbuCj-vGV(8XaT(h~pO$F1N!d2Bb@;7iU}MFV zq7kQIg#AL5!9Q@D11 z#_~In{2}ayPQ2Gu_oi7wBx79pQ|+K77D{umAhlS4EUX0#BS_t{hU(l&E{r8<#Q;8Z z{hS2i2|RV9Gs~~`_nG1cD86*MQ)jdU9X68^Pg{ z6%uF@vQpRm`Mn`pGU9j#*27aX%y-5)OW=COv(LdBM1`dS4*NuxnxQLz_FdyJlO2Q> z2t>P5ns?dB<0doGx@-1<=&O~{9CkO(G1`cv+Iyv2xRqRcGY6M5PV#FsJ93?QyG{&@ zoD8-286bm)*L3;LkdvW47@zO= ztFXO+{UvaVla-3t$xLuJBZ5E-JfP4#!)g>8w2D=;nRqJkRsDdBE=n@8s$G#_|2U8M zyA0)C`#ndSdJMj5hoo?(q`$7TB}|xGwxMDK$K0va{S|#p5jThDtMC;_&zrVIQ}&ha zn=FQhDmhRb_Ap!uK|25;*^uQtwz@eI!0lZpG1YISNNi+0;qafZaM%`g$M#a~BW8g4 zWw+x--Q=s1qMTAQmTjlSFj+wW_Dr4^K%_Bp@7;^gHzX94R5Y#Sh)SB{??Q0J4vz%lFDTNyAk8~=2YdxW?Eus*ups5?qx*O|&3e;x zzk_?2?+L5%WXhsGfmR>zt5Xlsp!aq z*qSHTs~s-2SZwSUDLb`fBa%DFGc$9%QyX9v+IQ`E%g|>)8Z~uOmAuU2h~lj;vvjsO zNeJVtNVY|Fxi+|!t<`pguB91{kdzn|LbD3MMjwQvw%wxOHyTW>CRzbf00}QNB7&Y&&qstMy6q*``kvu0uPIx)a@Obe>SWC zTeB%@>wa$8X$zF?-n03mW$vaG5lh0WqQgL*UWG3bV$k{-`?&o~A(rE167^wK21_+L$hm*) zZO2<$&-ySQON6$(%5iG&TAt(%j&a_n)BE`{?#YT;SAT0(Cs#9)bmO2 z%|ZI0G5(cPZ52?68AkXlf0=mXFL-&GIPTp^y!F%s@%9W;q}a*OaXxhaEBoW#@p`x0 zsO`Whk+eI>?m7FFt;e<5XeocQ%iG0yhOgQ!rGy!R76Wt#WcmjJF#11{w_gVK;Z=U_ z=Q-phOnL_`0LL+Fo)A-FD1KCb*(GO-0+?pir2*6WY(Ox z?vL~S?#&R7YQNehCz;RWyO1+ktRz(RCYsfTePub1DyIPVUxa$}F! zuy!i%?G&fw3AV`p?aIY&^|W2*y6`2L3Jp4|Z0KzILv!`tU&9?T%NvTDRmF=@N;ZCH zW;$3W^?+|lz?7|uf%4YJz{R^MiKJC)4~`ScZ57VFvPq0STEZgBi_l9UFeLzAjFL++ zdU)!(3%-Y7P;#sc95L`q`R@(OnoC&YRk!}mJF$a+TNO^efbLIV1h-w7pd!@ec+NEt^7%PNg zHPN%H)4R()j#2(tv7xfwXnlcfpIgxi@f%XQYm)^c+a)Ot^5>;p7g!`;%SOH7)=@!Y z?vv&98pEUs^D=bE1Mt*lY`RB)0i7tICC@Fb#jyI%iPKXGnUDWwF|hE-X3f$c!ur`h z*15fNC8_wBTx3)+OMu!=9cM$n3nI)G!%2vx!bG)$FVoBB$QuSzj?1-UROU20s8dzx zOU7A+dbHcll0UikfZM~E7$zdA68u|Envk?A3|qkM0-FK0SiV5he7?#u1}sDh5laMR zomFz{PB|!1g(TXRw@aM@XPi)ns+?(*NBFIfBDYTEFQ6__LZ8#s=U?+g-l|gQ73Dvc z@`{97s8aTRJN%HQxo%RKT=oQ^UC4KJ>@74QDLkfAu3|uSHC*DEtVTH z#EB2N0vjj&snGpjtq(shUKOv*riN|RO#i5L!6TYtCW1Bt>AP|tI``rE)1&WG2)mCu z>nBp!IEIERJTyY<7w~72Pv8_D^<*=-!TNu%6y^F^+3kF~A8y@a=Mv$+K7_v7Fz02Y zCvUkU88OTC>JUVi8ljh}Y}9W#blc-&hA5#Pkq$YmL^ge8OVn7^eKtn}CGiESk+Uech ze9&ML(vDD(IVqbys!^z@857|Xt1F8~$K^F7bF6#jYnX-r)V7UnV2AGt!wa3tdUdqha*!|(?x@sX*KHr)f!^Ert zsEAPYFY6^DjE{;hz8g8wKK%3C1mIB88NBC~Y4c?yY_xm@=B^_^*H z6L}<#{+9Sa+29+TkRM)C6g6@HAp2Q8~?gYG#^ca_VP+4iGAN!}dA>aPOMd`*#x z?E~eO?tLwe9DZ)E#@lh^3FkxnA~lhtTGC{Ud=R)tRq;l0hhN`(ZyR^6>-l=CtunsJ z7eKY268oum??&m-v>?~uU+u9=Z500E#&7-!GZB<3f#qEkZpiXWr5vH6xyN+=HFeOV ztEm>amv;ltUK9748ICEACzTtxDMYQWas|HJoTA!@sceuBjV!Jk*{%HyETs6i7O8Dq zgf^1haWkjdA^z~2F80shnn7iEc>Qc?)z{OW)Vlid^>(yxWm&197CRcB3x{y3)H*%1jp zwQCm`Q9wecyJQG69ZJ*;$jmg=-H#jg^K=dUq=(R_BOd&Z+nZ52m%l$e1xK^L(!1T3 zkl6Ss_`aC@@N)}w{Ozh?O_r|DeoU_{3t^ud;a9F;0Fp4sT%En7sQ>1nM-zYdPwVpO zzbYi`8$i$QVI|6q`E>HclUaGB+1n~lx!Q757tbQka@R27sNProm5s^~REq4I>5?=U z|DdelB+HMYt)$Rn%L{b*Qsd;c>=Y`+t?D;b+pF>MGoH}-Z{0H`93@&DWS=mV?YZFP zKQ{VJU0-KSe z2XTXi&wr>O{=nWB73bH8jhGhm|2ULhGptfE`Jr;qNiRN(JYha_6g145nYFqYg8C6i+OuLp zLR+=tR7SsDfhe)2Lp!Y_q9-z6^QIF0v!FTL{4r1)zcEA=pk$iP`=A!I-T{Xx@ztSC z>hbdXRYJkeu)24kB$_-EK3hjf5jPv}Nru|cE{3cvsP5VZBXuiD{)U!Z#@Dsam?YE%oq;&5fZFUvWlb1# zxi{JJl5fj;MDx_P7NFwjuh*?rcy8X7A`WGv2_W}$E#7OoY;S?N3#o7~LG{!O9Xr;b zbLcbSL6>D9VGd)1^}?nwY6Wm6Al!?StO~P}$Tln?ZCQ1?7Ug_QaYYDijw+8rx`ex| z&%Y?#$j@m65Xg%CU!6&qp_XGav9?L8G8ESGMw78&a){JH*W%p+J?l%OYu|RCy&$2( zkuz(ZC$?INkkwars^pI?Q*A$>uyJT1JlWyg{oQ<)%}~clmO{rRE__ftz)twvdLgls>lAg3GvE&w4MD zN0Q}Z#o;2gMRkiOrnrZJMYg5vp}Wbnq7klU%^fGkl+nQvHp*o)!R`nqU>h5`l;ubL z00}6<>J~VQnt$AXu-6r@!KijazPI^$9wc`)&}1KYeGl~= zGh3Ayc}`{@A{`cw7(s9F9?clkB|E?wUhhUMY8!W3gisq**sVQA);oXcSK+-JJ2Shr zKg7dxqKgxiR*O}otYlhdo`zHvxv>j`M zMyR2g)i|!zs&cHNt;f_YEN`g5yN!IE9zAUB`o23PXdxg}3^8upjkUTWoZmd>HG%x0 zCKAe|3(=qCLWhtR8h>}h?Ofjc{j<}ZZ7@w7dFWfE!5+NuG>^e5oWCT10n0em2ohQ4 zQGEUA+m8G*HIf-r0(B_fBqGSIK(IUH#EW>n5wq8gWm4Oh+MA<(1yrLf%g0xV9}o-m zbK_yK8@A%SFr*FC(&kyamghlyvYK}R#{O8Tq;}}09bQ%&_l=V8K}}R!ZQLJ&4N2O| zQQmnhtj{;)cOUL{V*tX59UFBPd;7E}=cpX{dnaQewlKS1yn9C`LB`eZ4D0{c2)(7i z{Hyd2GjDoLG-da#;`UM%(*?xOY5Sgmu?eBGmQb!gHB;UEsauIG>AF()27kCn&Ay0-L-vlFSml){>pM&DkTyAK_aJNq+`D+W{7~b`Bdm5e zAN?2u4tcmT9eQ3ni7$I0_IH|&!snvLpz2Dh%FIATW zy*1r4jBLJq{P74DQ+tRG-F&)5z&D@+@ABjjrP5>kSwLS+wa!w~szmnXLf~RU@Yu1v zH?pcbfl4gC;(aTDALO_8>owkEh+D#~885_BHidO>$G9P$6yV;Q3$TWaC784EKeKTh z16IRH3S9zu- zqT;3SkF>-fE@Pu(xY#`8+tv5WW1th4wqPD{OPaMFWS-sMgm^P0MUNiLX8yXKc_`E3 z9fEW|wKe+8zq*;)RwXcc2SO~)GcvDR#NK8W*35_*ci*uK-LR^9+8pr^8mSj;GMvaw zb&FFyOn(7uSPazAQ^w}A;Y;Le@}}wl2vd#;&v6Itsv_K#aT@Mg>;mB7A4tww^$$du zl{}_}s(Lc;1r8yS?@Bxnv7%1Bb3ryyIsbLTR+Xq#kV4>H=-i|k3>^Q>$-2S zrK!U9MxsX25>dT{Lh-dn_fEMSF1l7tm|1^NDC^$suWWr6-n4^nEoxz>pOeZntMsnx zpc7_p0ytYI#8t1^nDU!!mcV#>hp*SzFtRR2d()(RBUJ(vzH^QgUJ-RqkrdtbFRaY& zo;nDzLdp5Q*gu6bq(bRtU#!&ZU|D}DZWlY2o^uwdFqM&|iLGc|8ZAXUpHyzJ4<)Wl zd(?=}@i@0&d+-imh&~j0k@x1)_1LfPR!w;z2fwa3BrS;27P{3*(g=DtZWX>cmHvji z&)F_u#i?pY+1=b`9ysqR8$|AR&iE|dD>8+*Ob+<#H!I>3D$7sRS_MpqGN%uX)lJ$p zI5z^&d`=uN!7}$40tIsVkw7g`F_r^_?P8It2?H1b?Xke`*J#Qr^2Q*_TP z@;{>Wqzy*?>^z1| z+8u0|E?sqjJBxnM16FbdKAMwlZQ+#E0bUg=5TNNa4c^nR8meqidn$}%%!HZK?+k?! zY9a@vBJZ&cYMWRa+f9ApQ>t$ifN##V@gEBMHGSWKVwDR^?ih zb<<0|L>f{HWHUos@F_DOg|Q_<;Zw){0g#i1mLce0Zg`>^QzOBgxhG(Pug(sHmP|mrswk(0`WxYDH}g|>zwO3 zA*(af&`jPPGC(9h4NO{)%uFe{%R49nm)a`RufGAbN+^48x5@q~pdbNn73wsfNpwz! zTHm)Txe^PQ^&*?iJKoYV^v^x&vDar_;yJ#Zd9F?&OYZnxp%FC+&NX{p-6~uV^}%h; z-qpetUoJoVlB0k)j^Q!5{f@qR>JFW_Cvri4Mq`gdWI^-8Ih{yyKLe)G(Hf0UAIi2r ztj0!s^WVJChRrY|AauBA{DzO>qA>ny1)c>U7|TSzJNCu0Z2@yUUSXTV_po?|D@8d& zqgDDEbbeX>OI4Q7{fATs(pMkSpZNC(bbo(>!^#r(E!Fbv28?s_zqeS|P3e%KuFZTA zL}-GUo4v~r{`IF`|9N1gww2{dgrnx}+=}@9!#yMVSb3}}XRZ__M~asn{Xcm&7 z`3W9l9lQSFKIUPgLStCAC0b2ciigUSKz=FLaaa ze&OTe7>8v4aIVIIKC(aEy8^uCVw-+cpTj4QtCrVlZho-W#XY!d=aaxMJl{5p!>?Wg zo4_K_&^<76sntYMer@CQM zKT%jWTlU}eSI5d<=vB76G`_BA=1u|AqZA@zxN}?M?olb|$%0`{AOEGdX7^!CV{2V| zj9^k_>(gHzIY{#Uo-3Yb2vh488C~nYmTL1!@o1Ta$@D@&YJ}N*Xyrn6IJ&;k;PI2p z+sMI1jIj|3xL7~kyA^jQeP^iU%l`9(@v>iSl$*Sij%_#ON$1UKf%s99nKKz05_T2; z^BFE8eA`Yyg)7F!soix6s1lMS@5U!u21YjW#g=ICmI(Ea=Q%wto@80!qBrDj;QeCp z$)c5l?X~#*9Q9_5c!@l=N8dFms!+E=;TJ5N{do*Eox2tQzUx0j%eXgEqIy|>%m5qd z8uh}A94`}nY&$KLlV0M>t-5ZuwJAE&S_S5&6X6fA*tYgjsdLVWm?by@JZP!a)oAFX zwf9ROx|9!Q2PpL%UL-mnEBvTn$32?OI2cG3Dm_T`q&aVx;_h1<;=3FacAr!^8B8Zr z=$AVy1?C4ReFZyidhzkYxMa7LIc4?meaQOnD?2%3v&{wtz9k&pnY4?{C!^Q6?z*83 zR%6w*dG&gWqS<)X^_Gpv_Nv{lD`jjY%1A3hc-?H;5NzDfDm3`IaaGg@r4{O1aGH&+G;Pdzq<$)X2>p?6711KBqw-Fot1uVewdY0!R4knl!e-(A+*)P6!d>umDHLE+w zcBU{}^*?7YdpwO;->tZmHOcyN|K$P!Sl7{TTQ)z;u8tZk;oAnSziJa#6gGRg3%EwwZf)V)#k-i&cf z>J(+|B(j?Gz$_WlR5U!N+Wkb_dw)=LJ^$Y)JAtE{@?o+k^Yh$)69R_?o!2aUKEFss z`zKj93y06H3sj}V^h+Q`)DC~-eFW}~fV17RS4tWm8-7CaSpQIITtbVwAHcSnve&Wu z^-N@(Yf;HzTRmv%IFp!FvtqCCh3>X>;K&4SuU4f*$X1IV8(qn%i=?R_P8%Wme|F`9VC zMhk4%!ubi31$6mX$>ymlPsH%4cnip>Ug71(k}Sju1-MIIDC`| zDL@y{A!OAKdet4@2=}OoweYPyb2Usm8I%ML&k+YZ;^zoo+`%joxno-ru*ny=FYRMJ zsr!`6xH9t$twc(aIc2K>>4JE0Bw4$ix#+@#1Xl~7hn}!gnQtoThyoP zDiW}@ZkYA0S$|AwSskl`PUzAY4?jz@86B7X-HflujxF9{>yMa^q-t2+rPoJffU7iz zEfk|W6~$^03Tz}WVBFuYB6#o9I%}Vme=`5t?VS$Fubj|LV`=7x^)pLPK;=Wr@B8GW zNfwfgwUR&DO;JhJ`GjT7F}S_6O&WE0+4DG`Z>k;KYd2cd8%r>MvmO}yB;414-na!- zyv1d_FB$y@y@sn{$^_rrw|#|Qe}YL^W@TX4U$m$~Bxh(66oTs&t=P)j4aaxT44^ZnF(2?elM5$bhoxA?VHUTh-tk!J#%&;8|TsQoP!NByo@_PqAvIbee@zCOBSI z$nIqZPb`syAfbnqix0Hy)WUm|w*Gc}a~lPEg}@RJR^>hE=fh>74xy}n8JcE}RI5qh zFG;{3d91&@(udc9nFG^=kC$YjdV9ZPy00J<9&#C@9_orO?0!ibf4K@fo<6h#568tS z2!;qs;tjlHT9R=|+ClR;eWyk2Fw<_$6T8)F2MZFBFE)^+5xg?A__%%Aw}2C~R}|ar z?1KD$eTFqyuN`I8nZgu#NyUEGw_Fg@3NMf9t&OtYvlp8@@EKeDh!yQ92@1>Iw|(q- z1_*FV72PmR4mqdZcRzWrcL^2_QRWLH?=)h+C1Il0gUD|?Ug{1gX${Ooj(&9Bu3Gdy zUfcND{nKuc(_@U7z=YhF$l;Sw-9v6q?5oP+UTb`!9m^Trv*UaPXY0Me(`be0Wa~3M zuoX3WfQ=zfo)$`}A4v@X!X(WTIkWhiL>?uX(4}@6%)IOq*XRYp1_|J!|d3sie zg5#;FMp^e`o0pS!`^^KfKfdV`~CJ3Zt|7lEG0p!B((d1V^iy)X885eedZUj{1I0}@7odo zunU3I6^;=xv+k9p``1Dcl>)@Jo(Ve5$=Nlx{+_z<2{dIaPz}ty#4MV76m94F=bDDq zLc4*=*;uVb115d{Oft4V6KI_TLuD4uh}TO?$d1Z|w2@amtK3{Z)=n35{zC-+U+UUl zJ*REizPf3GoP9AOi0J4;7)zl-uJOjOexIXG^|O2b5{BIDtbT;%b2%!%^h?w>wZ~+i z@VneBej@E-Uf6>Ptf@U6(JzUSf_OJ9>Y2tG^>(HLZGP$&gYp=dt&L zmdagZOA4+DSz$qWBi-_uoy{5kP3;gkaXb~;0`A0e*JGx&mf4Yw)-enqIXin!wVnT zmfxD0#l!hagjxzxtpp{G`eAV`)1a=m3Ytd2mZ?2$d$aDWcrkwA4Y{>r%BENSK01_; zgdizN!OXEelsi91zv`4;p`pb|=QG>oIC3n3n|I&WXikrqSuyM9ct~eI znU{EfPJBRREo*1#P~ASukg*Mm1IDNPD;R7d#gx1(=Z zfNB6G_M#Porrma0e~rPJAqlUe7<^?s4f{t)n8B%90S)vJ=tHsY?_*{Wqv1fkH4}c> zeXZNv;&Idd4%rbeG5%ox2#6!Q--yaZTN?jfuGW>jAy#_OV)w6_(etU0wG9Mm{y|vz2bOvwLYM|;@7ZBpO>=j7uWrhZ{ukEBP-e$(4|1p`(Y`C(d?#_<* zlv}s~q~axV#y|7(mIl*t9xl`sE9dwrnmrz0;fdpvt&Va1M_Oh25FtU{MtwAZiXbfxZ|1drzBFJ+ z1HN|Z0Mr!iPAD9{UB@T!0G$u+&(XEy@yYQh{l`zmnbS8@cpC>qqL)IxC=#Kz?l;0= zt%ue0ek~oHY;H7ylE@_-++|C4yY!?VXyGxU<>pz~UG1MWx+QWUmN)Rxi71W!z31`5 zZ0KVgSq7qbg`w`wpeOp#z4p=JbG+nM6Jw`^yP=`ryfBhG2xt(RC*eZ%6 zddpY(FTE5yyZ`<@?6ra#*MqDhw36rw!j0X<^b&c6bGUmEM!9L$eF;)LwzUM^OghnFG}3$CZ~C1ySW>62u{w-!`lV2H_yE|1J63=A zMUC0MwajjryAy-p801Sez9GFw3d)Oob$bnQsR1%^3?G=bYIfE;S)huu_7q>P0Tv%l zkz#}gV)m}f9~~3p7lPcO#`g+V>Q*P{O#PiN%g}6AG`3=yj=;SLJbtQxj5}?}O*-e! zMR$0c6&PWr`H&VOy{lUNd)jGvnQ3{x*kj?0(QFwHP36H3vL3=Xl_|T*a0Tct5i_gS z6YHN!{TFr%rnI>|nNJ+i#AKg6>i+8DO1_UNDQYaBmEa&C)oVwWmRiR#lR!R_14+hx zTfZmc&AMjJ6+%Qx)}3z#T}si3k=_ts5@@qaSUgOqd$2*-@DA$DSq}`WS>Q~&wH$f8 z;{itu8D>tHxH_B|=CZ=Wl_|zelVAEoL|qUGcIIU|gHGjOM~3^={E4im8Sh=(ICy_5 z58TM2l+z6d99<=!cMmL_R#HCO?>RX%vrpiByg;|IKa^MeW^NAH01HgO#`_5ql~o?~ zSkh;SN0`$aG~AeO=fu(z+01MT^iQ?apF1>A!~Q+(gQ|)=&yg`*?5^|ac<->nKcOt> zay4W_STYn_z=0Z`bPs{d10X4BXEz#_~afT_{^t#e zFgp?N5g9cj!18HT_v;4s&fq%6U#ad?#lX4Z5T;x9kt!mADm$C4LMSVIq0`2nBMFjG zy$v;X{0hU+NVr_S(G#vVP9+hlEn4FV?x)WVi&x2|;sNs;cK53d)WXD7ydG4hSI1Gpmhnz7XT?;M!V7Q4&Nmll)-2H^=$$sQkLfZGQ2z_;hCE*R-_{CmG{CtKHV!E^})emu1SV9gYxe4 zVCvq1%idO5xKh=fI>)9FKCF85w1#>3Q!FoU$r|FODv=QDxb!*`{Zd4(qL!n4`;k+@ z_R7wE?|Ah`R74FL(jX=|iu1pVn|57;U`FopCylc#Z8Rhxn0^5vTwGbDSF<7ZaA#DxaGGrbbVWgWS!@cLEY z?*VfxL3wne@37O#+zq{kKt^>CrhUG*-(4n&^9KKD+bT=Q99pZ5aIMT;L40DvNgf)I zUa~=Rts;+zOUv&Q#l_sVDEll1uff<<7-s)lY@-ft#gr_(`|)(I@YU*Xl@TLu1k>{9 zTgFm;1u2<#5=F}!!`Qjh%CxNMWkG&eV-ZkSNUL327uy0Q2dui+enBQ2FR5|3EL9JXvZKH|z2XTMB0(MS%;Oo6T)A^lW%q+XZo?g81mg@V3 zvh7xi@s$zzyS#K?-UeKOI>TXAPQKGMZmlSWwF9JbD%+zPTCO(xSo|^mH*O zXU0JO+x3}+76c-1VAteb{MyX=)yzzSs)E;+5}HHOcGYjjM2f>jmDU<^r4-LfL5HFL z@@#H7LPzzQX|a6&!gWvh#sbg6k)F*r0weQG(URnNU2V9uJcL=Pe$#s#yr81NHtHeM zHG;p9kJg0?%zvJj_IN7pRD4eG%&bt>SzNfP693U9ZENJnpL{Lk7`h9!NP@|kWRDxU zmFq`e+F&@SS_C=vV(p%g2eRODRPUqXTKHvt^JX)I)k7}z2)L*v!;Zx%wo^2Mr)U^B zRo_C+JAHcgGvex3sm_?B{Qk7cOMAC9bJPNCYO2q8b&w+@pIR|iJj3)P6fUp#h;@`( zH+(Gcw=}ubeZJ3^&FrZWlJC@U$D50!kB-y5$$45eG1j+OQHgxx`62kMn+eKFjl=6m zA6|=gYv+eo^$$cRDs112e2_HU!l)oaa`{}KNt}>(eQAfBv_jlKHwcf3;8$5bOqV(Av!kx=v(xU=CU;GMfw3}#8 zIsVCoTN!&Psclxve?H}ypr>0md#B2UI?>jqw@6hg|gpDF}|My?|SvS+4 zg zU+=-0q2yTF%vD5EP3FYtjC_t3*4kbUs~hFM&@uGx8cTZ>J88{6LSLeq%Zr{vLepYb zKtE&rFiD{$knkyyx5WZ2naHow^~jLIq~Y!A5PVuprufv|AiM&;C_ar&hbI5D@u`yM zrnf{cv%UTQ|6`jZ%?tXk+c%j*_Et^Y)SxxnKjlQyqg1HZ;(4Qo7NPg)>$8QZexwh( z0WZtG8zy(|U@AdJ%C>0pb0-J?4XmfglTUErh(e1I!Rqbdr(N$f&IW1xHOW}2C;eHI zIks@loS-(6R!RL{k5O>#5XmgN^0mDivB5&htBLsIkiLX5d7s6;%*XoIZUFbMzuynO zmp{eUe?VWL!}@YlHA3tCWLBi*+T(A6{2D%XyVbQq0X}h98hSJ4c`R+uvxWUKJ zyZA}({PuOV8!uA0YkM)+@(IO#@{Wu1^t&_#SO27Ok`}`@XA=~+Qc}? zq)KHq!>5__c%S#tvx~Hs;pQ5IX#0I~&$a!Gv5FtOH%8m|yn})DHiKrVfbR2(KkRJ( zye(Hzf^rjG^V;QJEHL_XCq0lOF}s_3qyMMl*Io-90pI1`3m&c76^fc2N+x23&uOIp zrmt(hJ+6ZG{&4LB76&o3mE41=hWFV_aELHgJaxy!JUk3B%;p$&Hvc#mJR<0!CUE9@ zrkr;t?Dcram!$2nLIb0$bRt$81#U5Ex5bo30`DuE(d!H;L#*#JhFkUM5BZw}EnoFw z7@0$yp9UVt)gNVJhRgTHGMOTGcAi?Ro?@s-HB~C&AheB+XOmpNwWB^Fl5)QX_8xWP6U2Llz=Pir~%&%|mStZJ6 zg=xoDAPT9`^jhxeV@pjfgd0-fcMuHQR6PuSW{ru^viq*bt4%jlqAhq$2N_y-gCemG`PNlR;5u_L)!n-{`Q9JnH6CyU$Xu{RKU8h4#k1cUJ{ls%@Kmsu&!(dgOkud18jJz^RNlx>4J+BL%4_ie=_E1w|gG~Jk0kk zSxt1kr_}=jT1~q(`s~k(rHDxOK~$qvWpRFA4QV753Dqfd|2FT*ttPbzY?SX85}}>O4#G8G5es72((u zKRz${JKpHCCg)%Xj;Yxnt7$t!#r=TueEnYKs9h3glqRv@Iy4`Wq3H9xo8{Q1e)=cV z86DcNOqF3m3`r{Az6pdqc{YX?)yD1ksA2Y@wnpvv7ZZLA+n7V`#7l)E7q@~o=O2rj zvrF?dysbbggy^!=da|DV@^tkqb|W}Xtxxg4-+)>TS8e`-1@J#yjz1_SmmB{OGdz=Q zGL@YlVm-XYB&C0`{<)*jT>ibS*KJ3?qcalFnhykH@|ORM{EUk>9vN1jxqjYL3HtIo z|6e_|B6>3>ZXEsLWZRlP2Anx32s4xy9IaG;O=gh zKyVH2?!nz%g1fs0cL@GYs^06a9;3Re|G?#r%Q<_k_02i=O6$ttR5Cp(=P4Bxda#L3M=EImfJS*^lrLGd2-dgHfWje~{9>OFjZiBk~i3xupkpBxw zSK)yV^GtX}Y^%wi4iYn3EB==)t~d++Ak`UCD6sN1NsXhI&G#c+aEg0{IEcjgVIN%~ zKOb*_`{T)&ZjVsuyjTKzD6Ex&brvjYQM~wHD_!qbNg=;lzdELfmu9e#JSBceBn;2N zVuUqlxGr6E&No#~93!CUMW!Vrkl=|SgXp~P33~K{$E~4k;b41L8$0+UzmZ5D&^Kby z)Sj;`Vv-@b(W*3XxG;G4$-(@bi8zRy|BCWrEgynRC`~Pkn>Si{SsT}i2O0iM~OleIY1O|x(22k=B(JAY)x38ZFIRzF|Jhp)nW_Czcz_F zLTgix5B&`J3IP_v>bD9tnl^_riBLme6^e4<4vIu0)gr?nQ{Cw+Qo=@c#DP&NLItY; zCko%TBAZ=c!;O4xwx5d^Q_p94X1WO4OYPT>In%!XD&l=+OC-J(iOn+hq7>VTW1739FYIx-I!**`hj?82QaD)vLlG~@q3L-X?YM3Et4=Px?;PPG?$vHYYO7U=;U zHgI{NJ)ts7dTduip|E>=%5o?B0{QBDMRM_U=ZmoZ_|%$*j-=D zZDExR`pXku7lanD_t(`!AHB!g3%p66mZ`{^(%CJc#Nc@6FY*>DS&-H>(4^Ec)%w7b@=f@%( zrgZ#83uyJco?gfoqHSDdWu@!{%l@qM_qX@?ayMP?tL;3#L82S;(Zu*-g|vOJ!4q}} z2=BLNWDxE7!gHwgXu^&HCUaj`6OJXQ6Pp$aNAW5!wa&_4d!6SC+IR(xo0dov1~T&yN%;VzkoLJ zuc5d&)*)^1cu)-Ry2}Yk#8wGXcWu>~5k9*-A%uF08zJ$y-O#$^pd7_*maFTkHXFR% z{$TG^%;vWKJFCoL4NdzTP1uhED*aT)>lPM_Nqr$D8DNT;1U9l+Yf{2JZ<}|p!cHS+ zII0W&VlBOqk#4CV>_!$SorLGC`QJ}s|7A{tV?%h=1dY(yD9*mxHHD|6c}RRjU_F+6 zv=+Lg(D5DjJiYLld5ZCk2td0Ys%U~>;S(w{lr#=C ze;$lF`TOPaeAq#Gi{~ZL*PBd*s^=J;){J)H>-Z6CzBa;-;tPd7 zIE94%vcK^~j&T}8pc~f&n%T1fHg<#sU7}V(Gj6`{ULR$Q|JbwU^}k6*mrTge&@?} zfOGi)C5%5W0ug_RP_fY)XG5OxnkCqI-9glXbiUe{0`rV=a4QyNJxF!Stk3IdTGy`p zCg}ufv0kt*?Xds@JftT4`b>@BhpFK`fXiP}*Zik6WZl zr!zTiJ&Ns&hQel{Tr!$q(IkYFP5#!Cw>Qa2DXT<(E!noqz;DdHROo{`@<=6}qm1#E z5`E9}@xm|h2j=`mivr?DMlYrt5wB}-I)~kaO{S0ojM;c<_T^N@@H(kf%)yJK$rlVT z=iM|25ma%6+$xJHX0-xu?CjwcAz*UyLI~q`KZD}5T+Ymq?EU`q+ac4>zp(J`em8*#d@M_Ps9av(&e= z_Uqi~ZBZy4*BvJFReVlBX`$<>kw$)Oq0E@;$iNd1Q~K8O_LedyYHvCX8E>7+&fz13 z!}JaBunjNWiF8$_ov}?ap?PgndvSy~wD^lcnJMk({X_^D`gmKK)sMbu{ce64eZevN zY3{=oT2W!(4gQ6irEPfE3lx;&gz!3=MwTX(R304?^U35YC;>F>=|?K!&K<3XzA&Oh z+7LT_uh$cH>T}2Gq!TeY5~q#OR1}`$5mZ!C0b`+>2^j&bZSu2$NOb-97Z4(A1%I$ zGF`u1*sM(O_@yd?&w3KzZr=urw|-^_f$6s9l)acXkxsjOu9(v1CmENF!kZvQ%{p*P zwuipsVPKfO{(e1~)!yKIKu^Fs{tiYzJGiL7T@%nPIA2$EzN0Zu-sE=5WhA856eczS zY&sV?lhT8f&*U!EFCp>4Z;~gnZrW&bFP_Zev)=vHw z?A0fmMd%9bCmtfIm@WuKok-pKWXfTEpQwJ`E z%-xQ&An%`GkV#}rhM$iMlJD}zyALMb^lQw zgdOS8^uUr!h$$YkTV(}`FBhe?zqg{{jHiaF(8PS5p|qiyDPzYu?+|zLXUzG+gKcCM z)pvZV2 zbf0~{JzWZV$txOkl}Jr(&HlEDO>&PLhEs6E4a2e%@VO7X5c26?Ya1k@Y9{IaikjVt z{kx$f0D6#3E&Q%8hGZMD>at*^EIlyR{M!89lfj_6r2SlmOr;_f8w+2LmCBnoQ2P9c zD&}G-=i%>O5rRb_DmI^3yE3(C z3*&vb7|eem9w2A>aLHRUDy2E;*_vZFuVb3ebq`bHtCi2@NWM9osJv4@>+re_aXz9O zN4*!OnnZpJ8Uj)d66j-0WZ}T0eZwD$dY%`CPMLZb@bM1Go-{HwHGE6J=`-uWB75+swXYKWMc#d!qjX)T)&3w zdJe%3s`P4ui2uewVhwmm3(uCq8oxbbCvwL>t$)(3>iIZ5;Vvb~NawKc$;>+kH7K*Z zzJ8j!!>{+6ZEFlr`AHQXU1zmB6q6y%ZZUb_^flpK6ogJGN$!5*dzGAGu41I2FO-Jwv|l)jG0oHo0ZNyt`nB z&FewIz>*638cnI$!AHuIag-W{^13$&nBbdw&>=k5tCmbU-sTa0v8O)*^*KW1u=+O) zEvUUA1@pIbPh{`~9SzpPv3?J1L_9KmFA zwyA!KIQ>>U=UM&v2XD%3S7hh!OfpEh zN#Zugo&5TI{te))9sS*)dQ`>Xki8f#@A~b%gXfIeoXx3p#r=FW$b72yZDfY32GS#N zgj@_pc~27gZox7}DuzfNP^#t!!Xdeb`gk;;JOZUFoWR}s;>YPb{A@nMNZ2Aci4L{zn(z z>GMdZdT1-E6MFvr$)(KmI`<7yTrp>p!|z!xv-JEPsY~?y`Wj4D;z54HT4o;Yjd*MQM>6sP0(3tdS7xfCY;&9A! zql)^bOo2y!zvo1i5;ntlr@3OcU^dp8UTqPjZHO9vWbyZY z9KCaXFB;;mzdcHm!L5`s7b^92 z`MtkF!}76KgY~WiUp69H-(DXN-+se*+W)#oq<4qI@{|CB+Qf2pK`-3PfZQXL`Z!Y* ziE6jjm5?%-%!DYP#vkMVdM(wz3N?U3qhPz*W!Gs;g5K)?_UUA1j%#ZQi3H25cChf3 z*X`T|OP{WQ`Lc{xJgaX|=5msHm(Rmm>i%Q_VuE)4oL+|IWGK!J_tUO4PD{BBPa60(>e z5dl3!i~1pX9lGh{cuWgNhOt&MJ$~fM|c;>HF;2HG83o4GNG5m zzvJ|Y7~AjuK?7Ora4IE1hokc7oH@0LM$a%Fyhkwv>6qw-0=3Hq&RYw?$@*#>0V4>J z3hWb9G{k2Se;2gV%Spz_mkxPi(BZ}`AfcQ$(nhfq9 z1qXno+>^3u1@?eL^=Y$pOqMCoZ3hy242iVp9**kAHS5%V(>~d%PBBBB_s-}IIzeEy zMXVSU=C1|%Wyw_HsYl#_$DI5e{G;=3&EYqrGxsNLaBKjDR|%&9RHQ^E zDe8Q4hEL#%+&fA=4Y)aS7*y|7jP`xx)b?vKVPkx!lQt~Infr-Erg8En+aH(t<#5-{vB`yHo6Ta z(BgeFNR#H0y$Qnm>#g;rrr|B_q}{{h+4`UkB;#ekzys}|B?uF7@R$l^RbDUm@_ zAqeY~7C^}w%*h%kS)RW;jCv{3`OV75whLC$pgGa-F^2FQ^kp3nAsCA6vsAe!M_bWT`?u?z zC~g15+>B z^WVmC#-?BnHUpl&N0a*=BcQ?KIq%Q*Hw=ByR}cTm@noa?8Y)d`?CJ#JJ1@Zy`to){ z`$BFk1rhJ{ecxnSEZ%Z|_syfDl6)bcAY$bk?ALblq<^g`QZ5{~oqmU9yAbdn4GuxQ z{ipF+v6sh`YgAP18+KaLf#0zrj3rkV26i>^C?gXt7NMN$5}F~pu7A`zt$9qdiu%BX zW71HxL`p;x3^rUm5VtvxAmUGE3flgmphK9-Xbw~SHC&56|LMlq=X}+zT)!lKH*Tdu z^Gmr#<4@kmIX|F}vM+Q^8(r5E5sL42+Dmr*JHmDm)!;V98-XEly8dHI!E&`-)1zFc zk)j&sA_qi={yG$$`yKlB*3aUjbce5p4GeAqf(REphV1TaCe3=DHAfad&L&mU_GW5O zHf5!C^+Hjfx0$BpAPrj2=a_w&hzjr&2%8KeY1UO4bjEl;;*Z1`W4TRxh~Q5}jprt@j~l}MwgAh;w7#{W0-+KUe{dzPiNt6=h(RPC4?Kg9R` zg!5p+f`4mH4wbvDcSW8U0=N+WY*{~W6`*Ir#(k+D3M#RRK%crn>|)sMFXnZ#>hIG> zjIZ!hi%6K1RnYbLL`=8I_UJ2k;NHDkIx(y%5f)0Qx7KDU@(w~&L%l@|o|*D4m+i9L zhR>aHOjh)xjO0QL%?a9qfZuZz0ygt+RG@Pb_ItV8esTO5`^m|&HI=|eBcJxoaGf+B zv?`laHE_hR>$xyGn8>KDa`tnT$NO@#5=$W6#!*=*+6MS$I|zDRqMZKrEniqtg%U(V zQ6^#sg|eY2luJChdf&tM-m$oTu?+;@fuP2dDpi}qZ#ob{Ro1uAu2#%PEOTT1H_@VP@aH3i|*4xs$=$ImM0D#T~b}+?Ep1cD7COYY&mNC5W6`_t}oHBL+^JE2QpNbE>EkD9(!Vh-Kpig z<1%wFIiw`FbH85&&8knJv~#LHQZHHUHu=bOKv7`RiOx@YAc`;k(#~>c9~NZ59ROI> z>=3dI6KV2&PI0@i#5wQ%ve+4yALpy*{K(Fkl(Stw2Rgjwugji^0ywCb#X7-laq8AiJOM%_%^3IMW2{1lRjQA{cPsV>%@%kb0R^hz&YC ze`|!}O9PLXh7_#lM>mW(vu;x=0#1#8UX#hNLb*Zz>x=u*gIfd|ImFUD@X27d`2$U) zU%=mm84)J41%hN!>fYe$M-Jomt;jG|MZ^k}ikzv_IjlOwFovoXvf5w>wz08cssHm3 zHI&t`?_|>DvZxSPF_a9O>Pc9`pdLljBZ>YVFZ)Yy>uAc5*8ls!v*m#&puHx3Jo=8- zwm&*3D?!AIi-kt#Di;jFedTYHPruXTb#?4kDZxfN9%UcO?tCeAHd~X$FH%{U40>r6 zxS1WuNH1-xUO~3*nb~;e%u0a$A1C)7j|yR6+AH|r7iD-bIBb)OCCXkzt=hd~x8(CD zB<{WmI~x1R&-~O#XRUR}07*Hu?kRfYAXrfUCFkb{&x<&|vM@IUME2N{dtg|xBsIIz zA{LjHN;tM@~I{uD8v6? zOs@oC-%WB=iPEHxBB5*>EtISKpbV1Z3xjgDq*XN~_MiSh?v?E#+ z@$az*%vu1JP;p6hA$NKFUPZA#lAUD5pDhNaT0EW`o?xpW%h%+PyIgA$Zkw#z;sN0) zdUbs)vrwVVHPLN)>`cI6$*o8#;7yCo^zHQwEzSln>07M_V8OaOSzu_o3LuZR$yi1H zXZC^ekgIn*809QiTY-@SUiTz#*URzxe19-ikQ6#VH|*f#^xIs2^p}qWU3&e}Vxw~| zl%8*{b_cfu8!J)Bp%zZD#^p_%gXMfxtuu8Z;Bw6sj2s(IT}l)Pweu&*RqH96{7!Qx zMksPk?6&xrD}(x*m1+`S*tXk0Xr0#&bacAJw3O&{zgZa4H;)qU$N()Jyge?_hjTbUhHzR zu$MM-R3%8-D8{(E;iQOl@0pLHoU(k#qLjInaX+Qn)zuGY#4DOGgbZh&2GZLxf=jV! z*^3~%I0n-vtc8Y-ArY9owO?(KF?DJ~E_a&1CcAliL2a;GLy73kHg-N5&C~uX`j$0d zk@?xoIn<@M9(fX9WFP)sjFwBYrIK3ikJ3yxI^dni({F#cq7+a=SUSjJWRg9UOP;bY zcZ>AA?}KWo)~Hf5po(|&kQ@LkP#oU0Y401#v0tjV3tXN}+o=Eo3&Kd< z)A(3J&(^~xTTM1^nLJ`D+4{K6|Cc360 zbiA(j*s;L$r;`>}|Dg{N4~>XJ#yv;O>zYch*6=O{sIREjTUF6xIjQZ!KY)Yoi#?KV z?TGKJAg|laJ{`TrI#CF({~4MOdb0F!Ku*`2)s5*3A{;e28ecE6xc6Qr1bM8k1dvP^ z)_5;|@6StF&sP{HH8*^CbMTPyD!NdgCV< zOUdy8jA5aatnE`ZG?mSnC6lsPC3z~Ntq2jXbP$T8sG2Rk2OUx$+yls;myDJwLq%YPMWb%~m( z!s;_fiO+2P^NG%y(hcVIYg|^HT)gS30sJvPo>FSAW{2_z70CwRFXMOICQD*)$cf6k zJZr2-Vbpw|Kl;M=Q2fcaW9v-P^+Cj=gv5}D|aO@=?eW!HiqW7O+Zi?&p0pZFX1 z5YV2ko^;FCmjuaObV@LYaONNL4wji*pPw;F&XLKSp^06ZGrs%|2}B*G0aLRjxq{o%fXFbteBI0S@F>dz||x=n+(X3oSsX1*ZeBQZq%MUn`Q%q zKd?ql^e$2uh>@qaktU6iO0CXCzddsA`^LWY@qi-5U_BzO`J2?+uX2%l;=cY|rh&-d zY%rhjhM)}tgUh#D!wJz|P@*xC1&f!wNMkYR*j5m4c37*rZgaC%Nnt)mKIMqK6DO8* ztC({8>u5-SEyYHyo72_xPgHm>r>Y_T6Mp)#DX_K-^H})zdT%Bi6KDZB!AhAengWg{ z^)H%!xNcI!! zg7&3Bo1Zk{@0$picZ9jC((IZ!`D*8%IJQL1elM{ywJS|l&1y5)e6S7rbdU+^w8g@Tm0MB&BsfjTp^idGDdFJSRyv9 zxzHXGD08B-g$kic?e;*AUIab0cJgEf-3VX57Xo+Pw~VW7@c-+V2K<+ati}-8 z$dUYNRVupRbN6ODpy(qKbjM2wTISt#fniP({|B@;XXr4js%hG}R#iU0@0UzFdC9iB zStZ`q5;Vwsg%nPfE9*O@%3AtaUFPA=a|hA;@k~8SrD1nCsV-Ag;HB1(Tx+89B#}z|%p8C}_DI&BfMdH9 zy?^=*-m4`axTdCfZAuVEW@CV@f9`3A$CLP4_hqi)v1uzjuzWtZhMf#Uf<%5)Hoh-Z zLnej5Dg8muw~Q#ZJSi$2yQy0?a@CXN4f*rz#P(ORSyjK!e9*pvsszQkzH|k2+Q~$| za?vG*yTce^YNqhYd|Sk5@L?t|O%qs5I%@ACcYk)o*v(h{Ez|uz`?z1`&X=8|?wLQK zT{0^fLyNcVf*PIX%pYouUyP0BtN+>6aZ#F5z5}+u!mV3euF*rZ6bcFFhtK55MT#jg zt!vczFv#PYxd;kmv${w7WN{);BnIFa{zj->&tMrY+~utpM!4C0v37181+QYEDEX4e zgtT9yGdL`SPNEID=+c%IsG2CS*6XiY%|}z?7af+RZI)I)gbOEM3?V6KX~r z+vYWh-6ol_!7Aap(Rg0zQt-`kG|@`(D?f@`o&x&S9;@o%8FTCWP~;dqVwrGEK3hQ&m4d(P80$TZh6R#60OAQLTU!hM^Zc9ORCk>^ep;AmrNoa-{0gqdjaadOJFGS^r!HB5;;Du z-4gw3Z?A7P>DR4lxjBLj7KBan?FGCCPuU>#EF1*I*ts$_R)3OCY{ZqX}W4}^l@;TO(^nR}eDjq#Q+|n!^()>bbk6wSN zEHY^4?|@Ul1jKH=`BVv;iS4b8_rsYeXF1=ba=%{LZb0Im5pI=GPu(s71gn01^3$tg zL-^I-YZGWBNXO?nMWO4zMY4x=gOvUN>(~osD1o#7D?U)xd@{8*POgGHB$vq=0`}ts zaxzcnzAbnP(%$HF@xAQsYmR0Bk=C114o!E#^SjsSUtJKn1G`eI>#>X;hDGk@&t=2< z0)Hz>Zg+T3zt{%{&7WL;!B`M3^d<-MC1ursm(q2UIFW!xBSjoeJf(Q(5v3x_gRTGJ5dJUtA z%X%2o4R0Zmn;X3^9xYG!-4`j0bnx+ds`2zosozT#iV{^O#nEJzBwy1dMN7&FN^5j>Bh0(JlWj*Xw*g=Eg8hhpp~_YRh1s zY=DDqZAp1OcmsTDk168n+w&mIyj$;mi*;igzl_ku|2DQ%nl1%J-5xUKqf-vwxH6i9 z8*MU{;xgfJ*^(tOD(n3&_s3~=_Er~5avaNMGx@0!x)4*6?eS|BPHy!PMO?JKELugS zlHbX4t0+YcaFc8(2)k~~b3%rm<2(x$o3q=+=?kAYX$)bL)j0)vasZJt8Ff?x-~9b7 z6uRNEm3(n2nANA?))x}xij|Zk*ILXkC$SCXCcG$-ByG>>$;AGmrLs^!mmGMm`nM*p z)a6(_QP7x528RX$S=%S$-Ska8ROzhs8E`;ieM&rkdVcNnNGzCQ%a(wMw=NQ$eD{DA zf4^fY9vbkjqv+0yxCqRkWe1+{!`zek-m6ePe=Kjz*0{Er#plt&o+Ew^mZojWEeg@DHk=E~CNpx*Lpman;iInuo6T|QCN&Cq z7$R(%_&jV6dU8I^BEn`vQ0yqB3rN||kwA(HdGCV`S0VRdmM0j69a{F1nN-s&YZ8G2I0qu0p+Xk_sKKWn>|^=i0oS|K)Qa&s zm?eUxIz^x5Gc5zy1b|`ThEPa3OJZf%4?hxH>xX7X9%C!&SJz&mg zU;^e0yS1kJl-nj;R8iborfVsu^e+xg+(>s^HNsQ|#Z)g$MOH$GQyF3br5Y{s7O!{5 zn8e(cA2THiidpp3gW;H=QUIfOBi--%f6H+F7cLKXi~xm;2CttUvnqb%AfQSmGep)u zx!|mHGQdX1k+BaEcD-1T!Vv==Da8T=HhPL27eEnMTv5n6P-xm!OU~ZF%1NC*H8K;xf_1RzV$EtB^z%XL!H|dXsr$+}i5nCrFS$wthxWh2 zQ{6u=Y=^PQFx=FRyCX>WeJa$JDilcQv(Is>29Hl;%hu*M?%wBcsW%9P_t#JjOFfsU zWipo2=DWCyJ~+8vG76Zy2RFw!o~J0&`GK?us`KQD&QFmFw!~Kuxu5yPfl);mhjUnF z<8jpPUHGXHxC>4+4qXRrUvm%+QEqf-_3fMQG3IRC5OktH1;&+a$!|Wdw!Z-U7Y%pt zVF;9#B0F4r7mxP2geP;JAZTwlDv-P{^=sEiA6l$hlNJ^MTvg0*Qf%PK}bPLPm_u>WCMN%5|eY|?H)0)e@q>f@TzV}kO%b81A zF8)Gqv|dqT4~4o04eB&slyZk3yL}HL*_MIo@w)i#W<5+lzk`G!M&bu{1>=ZF?y$K| zv3hfSAvH2AL}dE(g0o z=Jz2uypf`QY`q_+7TC7cOy3HDM+uE$c3mq1GPhh*+qh9@k3qlnb_biC}O7BLfo+1JkO}e_+@mc}CgOPG(LUMiL}C65OsY(`iJR zf}8-m41vcSYS7UHNxQX!h`~$Bd)f689OE`>O};n`50@}xRBLI^ed=lY5t&>w#lp2v zt}W00WkL1XYnQM5xB(Zn3mOl@S`K-P%qWyQkvQ?mi&q90Q>hi^ zc?UoDHUzzx^x&ZqlP+&8FtvICSyAC~B9NFLa=q8Wj(^<_LCcO}81q+<5oNac(CQ^N+7)_wT?Zu)ZBc~nWv=F9xUa2+l zSZ&&PAjFB}QY%$jti0&QD*Z;icC^}P16!`z9%B5YQOQU9D7mid6sr!~qR{_U!R@#9-11_WuUzk`B#6IiCp3lx+1|4A!WM$cHxalLsdy1DrA10ATAITFK2{?^11w^rCM{71K$o`Ch(h|vNjko&X@#a+)FOM&(KO)o_ zg;IgIu+pQwKI1LfjDBt(LYTN;i2_LhFuEHrk^8>C{&=Gu`GznFF3#(Im#b1G9{$<& z?61>-R_7jHjgZgryf|^u8RR}hunEq0%&@yfp0uoX-c9^7_Du&QARQ&IKj8QQjOTZ{ zH)1{~+BouQorto~X9N8M((-Vx~if2pa2$-%@VcK`w=`3)uZXeuio z@Qo2C`@POC#g>qYrP9jS!{J8jg^RgCj*O!OoRkyn>XB30|X@-2hLkF(2mo zI!ejwvKKDByJkmOp*rCB&|P8+WUyM5RzD3=LbBw10+)!!ikaN>JW(=0y|beK!tID1 zrdM|h5p8J3AKH_va}mr_VM9j^Peuk34ql$2m@N-XO5`xa={`180{+Zasg2u9umyF( z?-=x}u;&2TE6k062T3PWHC#=|_^|5fwTtO+6X7B{%)#6emaVzG$VW~x+SzE(i0TrF zDiCXq{{;nB)2cFDa%jeW-BLMhukz9QlH{r<`!q{k2)DBw%mdRz!X04v6_XDm3`@p$ zZOs8d9x*YZ=VJx7|An!AEL75fMu0`1sx#lru)??f;g-@`oc7SRi&|Z9>8(^tqDt0V zU1*1wd-cL)l5FY*3moXL-A)$^9fd+D<+x$d%20rJY=I1G6_jDTJ8*c*6<6X}OEC^V zl6`cwQ$S=bLI6PqFJ~T$`(g2XbAY&Ebj0cKPGR<$PY)hkuPjftaZD@pp%VUrzY69J z%1xO4>E@t`FMDN*2c$;*P8T4ErPG@E;5fJDrgaU(yHWE z=w+U~@2!=O6x^?%y!i7Bjk*i|NI3>OK!*(crCg5!vIKaa=c-B+g>;5{0-yx6U}!o4 zgA$ztxY*9KchAt;InuA8#?Z?sJP*KUYV-^kRcFI7A6g?pdHLeued{vS^ao%!5vNPU z05USUn7698>v?F_j5xG92+WmBIJn%*&q?3xC_4&+CR8x<;&nKyA1W3ZFfF zDh=~KtkU~TSWo!kfVRY4VSsItQt?7>nfe0~7NF-8f50^dOpu_}J_#bOU)n5HF-PFp zo7A;VS>sIs!x&d#q#6rXpbu)*1{R(F+yTOKe=gpV9yo>5IVq2Glu#tKZ1Vg$rWw<-Jw| z#+kh?Mt7Do%WpUM=bMe1fkN^251C#!`&Jit(fn{)SKyP$o+Ls}yHo&7>`m@@ALLxC zc2GR<0%yLGh)C9$-Qh)eR7U5&?w~wDh^PeYo#n~Di4t&{n?#)TaSaQ;t`TkBYaMUZ zS^5$fP~uOinDlw+cpaZ~<&tWLkqQuH5&g`f zc*m1Do{RJ_Jbq3<#bR*QlEI_wfWW2b-_y*Yvx4Po59S7(Jb~wPix>EG9yg_b2v9$2 zR6DQ#LJIiZrp>Y)jQ}y~NUARRp~)k3J{Bl=ac6wdbs>zf*GJ0Znf_4o@l3lXa65BH z?d0(^rrVZ(lNO;RTpWdwL_tkhW%^uI=Y+xrZKrY2Gl%W65%q5buojQU;cSk7$VPLM*yDG$NJgz5wK~0UjNZZotWD$^aG3_4E61uRaEI!oSE?pBDy7 zq9pkC$-7^>oT2beQJiA6pli~bbSwrZ{Tr45FJN!^kzWUUV|mu1cKnlnvedq!r3Wm& z#s8Chx?B(pYNPe{l3wD^K^(w4fu^z6WtgKP6`=shm}!{Y@J46yS7SSWYJx|O8%}`?<7W?f-O{+gU9gDLBm~%ypxZ5) z-pAd}9AL6vYtSd4`RYePR1ouyeDhD4A^w?i(I)Lb9zCo5N1q0@S7J76n;z}y;B;#~ zl}EX6W|r3UD@jUFa9{KcAxiuoSUv7gM&44eBuT%ZPpBW>vL)4P+jGq0=k>mu`!b7J zG!Ckl+CE7pZzyDHEs}k`=)G`Z!GcUf_QpnghUvQ?iX-=CdCTAev!yb=B!A1#?>ZZtSk z5W*{G8Olzn_Y-X>ibPT(0!wX_dks7o0&g%&sX$WwWTl{9EZ%0xffeo7j{`5TkhA&P z%FplyYWeOmm`+u;9%swB+}U3FD4MI{B#pZ0F>FqxlL25}o%ov_Uj2ts?nMPs6S$5e zfOXa5Y+xPJ?`od&SG8t96c0p!!>25W9s!vFZ3%Mlum(P9O((G5?m>OZEdH zWnV%jnNguX1cieUrCG404W4y^7PG4xb12rFRmW8Rb8e&UN`U6BBNI4`GOXe;Zt7)e zo6zQJXto{i1BGw%?a|m*ru4;IjXC?~0(U}~nlEM%IkIkNfQMD5p#gk%FcLQ}p7QKA z&9KAwH`$SOv5ECWy81D@3rM%?8>fRTsyGG4MK56fGXdM@?0@h14d|(B2#$YH(2jqz zc?^zn&R6HSSEVb5R%ld83$%H-gSyh$ujW2_$PG*%t0u;&4rmH?L!7dSV8I0-SnCla zr@%+5J#3oF#R|dA^?~&t+;`H%GG+?yLs416_2v_*&c;V^%3cP*sS`nb=P;c4m=|W>;K(1=!@L zUiJtQ;Vr7?5i#pDjQ6@}e0}wRjWk2TpEax(4k9V$aF#?q12l2cZ2n~7LVfw2t1vvU z=#3P;52Y_U{zdr$^Lj+nQC2+N{5DMrwT}RvhxeLJ9>*nxF)_AOKP2*;x3!y}q z(Z}qmki17A0x+AMTrSrNc$B>Ez`h9A0ZCQs)n7llye6*e%p%K-0$*h^v6o$TUacbT ztMxlnKGq5_yZfPCshQyLX*h?XZJz9t;0>hTK?BVmIw~* zT9Z73^?D2X+pCLS5xua3BRw(uV(i0teKkp$snWS#o2Q18pI(g-x-NPDH8fG(7pvJY z81^Hsg6ZZhFqj5;Hkn-~L4kJFmj^q};|qhe{F-JX@{0HHt|%h5sFQ`c_juF3fv@x3 z-PI%CS_HPcQ^a^EW`F=d+Nnj*^Zm$DvyjWmi!w)^?Qoq<9|AwW&!H*EfJ+BF-cy9z zX3@0>sB_p$7wes48iXCanu@&Mcc}-dWC-aZr5eKfXDjTbu5@dWT*|0TAl9*@3dLv*yQYO-ruQUc z%SrblR@$|Te7dCcaJITYR5^rpj8>-3YB5PfB&;#4!_&R{-1D|JGIM*qH$1LiS6a5# zNMe9|#t!rB`)As?>DdU{?UC~Z4;P0eeM&=hEO%f}P{3{#>13h38lz-OyUmmwn_f*R z{2}?1OpvqG{}|o{tg(;?P+!pC!#Dk2MFTEc#R*aLT^!-Xd4*dsRuWVizn9UPtKGJO zlL`eCalUI>y*Ihs?MA!Tp`L&$OivNCX%+51@^t#aN~A&YDVKsC(kzK|YzwrR=|IHm zIPQ>9^jsKzxR1JXf`(_8zqnFJ;uJ-1uEhcZ%~oBI{VAtivFrBDE1?WyI2S+bJYY3 zEDQgi?RWT^xe|AhRrl9V6IQE%PbQc@BIq0$mccb9-5jUb%@(uj1IiW1V@C<4OJNXMWELx*%D-9tCbyXQP7 zJm-mXy#8O`Z^Jdi%>J#t_FDJ4SM2`RF~Y}oG3<{}WUF{?cjF811Z0IJk@)m+(Wi32V5y_jbnx*h0rmKLzQ?mWg^N~Rdpe-)*mno)krV_J$ z66>d;2=jX0ZZ%k%yHcm)bqE8^zr!7F&`0QjgLmB|png6wp(k^pRTnR%xt0Z_17B0W zYifNocSB~5`sJzG$~QW_C`@+MDX#}N5)MFpT9W<6@h%Cs&5;Gjw1s3hn04K*JCex+V$m$Zx!FIfNOM2gzYm8Q15Y%Oy+F+Gz!dZGSD%G$~%4Rm#z2~ zZGUapY))T8v5x;}$nT+^rXS6q(o`>$)$y596fK8ilTsthiDQYxWPa3fNuZJ7(zAp7 zdr9v55^wx$L<9TNsnYo`30kTKZaglXq`U#I)_^Em5s(KZZ{YdeXg1qNR z6^=_3IwcM~c3y};ScphF_G~IS!ePe8pDf-&^c8A!F zvQg0mQXy^MAO*EsS@Try>HWzYpV-gknh$t%6L}mghKMG%3>}BwB6$m&6Z1V6JIT$R zn|*q$_8=2ae|^`v>`+viWE1N6QJ(y2g6R2;d(4Vf5h-$JZ*%Rdq|W)%W!S_X6$Fti zFNY4V((~X)nk~IRl}}tVySLa7w6%J!89Y69U=St4Sk1P+TUA;;GAkjN+*udLw2$TWbF$4fVXo zIg_4bm{;f7^r{HO*y@T2QC#}3b<{nz26xY@HoDR-6EGXUoE{ zTFUS;OgbX6cDUjrA1zAc@^vynl-(Ivh1kn-ki5BDV^xKL<-MFitO^=crJ6MeslIKK zgW_)7EQQ1<1fihM8T!WIp*dS5@tsk2(3}xxroe}(i-&uD+Y&=cC)SY%&!qi*z%H3a zo#e5-&-D>`k5enkoIQP}TgsAd*Nok!RW)nz@pR&F^N zb+X4{@Wg3Q*w<(?gj_d!sa<+rt=%)SE-QA0 zD;-=D%ZggZrn<(KUySuyz1E`Gqdc$knDY+GYrV>6FBeE(tsU*4*~ph6{t&fzWX;gyY?l0d{{*ex<1mQk0hYYjgD`P1SfJE9$@7`gBt&r{=f}Bw zj;Uu~8>^(Qh`+r`_o8DV@=*+;Gle1ZjE$^0j3TmDzD8Y^ic2z_fo-~P7>alY$T-Gg zLn;WKlYP|#QICr_$;e)w`}wUlrBQ3?1cF+hTW!*xXnT*|oe>#>HKn-xTlk3pN9DjfZuxU9FA%F4V|y@!ZC z3&T#TX)%Yyx>m(88I5R$uAP7IlodmUpj%A}7@*L{rx4r#M$y%qb-P|_fBztaF-mXD zxRjf|MJDK40Q<2{ePe?>(JMa%zopHIYSMa4M=dM`%Xu2d@ z0+;Td?hn%%xW3(q!@6XTd4*I0)R3{;TpOk;l;zR$drLl6Nnd5@E+}rtyh;%P56d|< zR;Mhq7r%bw0}C-vfBQ^*QCGH!^m5}dV1>zW9GtJ9=@AP$S#;ImlsO*6_)Iss4k$F) zu~0a=7h{QLw96}vS5>R+BbEm&02EnLJ9ezO}&A(GUh)%@`+ zp3U&CBXKfUCD-%Ok6tRx-?^IfL|z&C$j1IoL|;3TSp@kHvg^6^PvYAl=ESZ?i!CVDU!0mq##!#H$mph3qy+R*}FOR$AeKG zCJ4xy%H6m_=KU1j*gfSfv$WZe#pYWUAN=_SYCl7jLH5%vtE3}DX6sdn{)% zWXHph~ij@Obh7Sio8E;tsD$m-8#1~Aw&jjx<{QLkH zuG)(AmP0fJLUq zAG@QU6L335ax*f`31?o)cPv8+o290TtnqOq{0#?TpcE3T9=q_1XZ zfT0X1j zzdOc>MpJU@5g2Nr_qxt*x~4_rMR02^6JWC;iWxmF+C9eeCY|^0$pOevcbFa9(j=>gdQ}OOD1thoFKm z~;Xv=?~}5r5{z;XmfWNH;fm5H?i2BeJV^5ku+W9 z*Hbz0c(WNz+zrhBnPJ%+DehkWA8OCuHs?___(}Rti;MhE!G}&_x zXUngF@9^CxFc|aw9zyL+EE*f{vq}mtUoq+$glIg+b$HWV5-93@+CSeG<`@6S;3}r; zeRQt)iWzj8J~q3Q>tpr|!aipSp#M>pgjLTeC&BW!5tFZ1T;Wq$pvKhYHt~zyxWu(F zKq$X5u{zvrIk_3!PSc;GEYlIk`W{@e#BYjymoO-JvB&TsxsbE{$Ntp78fWYNttXOX z8Ro95VD{H!u1qS)u;O?{f&QwdxWDM7_*$0@4L-7Cm@Xrx{!!~en{|1aeUr|? z3tC7N9c>uLvfgt&`P+Q9*EOn1Yd=dCyc$LGJtK7kF)0g18+Q_2iOyc|fXc zNq41UJqJ9%7Ud(5)JH@TsHVMs+=z!kOStk{>we@Q7%2pZHfW9Wnk=YAELorZMu(fL z^6o{F@Fpq|AbCK?^D?-=_Z>)8Cw>WBZ9#bszBSz#7FG~8wC)Qs>#KYgQef!N@YiJW zORx1lJs0J%>uVp_zE=edS4woEsK&MywrSJrP;RfUcWbY!-Y{qWA+l{yyUq`w1%>?)S8VpoGL@?5)JYuP!S8UH z+b>@ZlsZ<+Q7UWTre$K#neWFGmjJ`Vs4tbilL+|6Q0r{Nqfw)FHHB(z5F#1Nr2fIQ zEviN>23)BvFZmkZHTO!lHyHlyG{4ND7B2x};82AG{-Be?L+7!n2vm{LJ+xHv^7;=!Hs^o8p6oY0Od|G*Sdq2D9?b}65bHgrAsF;y#3FPazi#_8Qg z87}IB(?Je-oH)1ov`v>U{o=G^ZzSiBSX@_T&nx#9=cYGZ+BkjZx8B`TKYKWk?e+zJ z`SmL*FwwJ)xh|>-3>V`aHeq)RVg{YURlKmTOytp_zXAa9VkS^osldz7J4Qu+|HTov z#{i*REaTJSLq00<<)L~$+li`xE=%~sa%**hheV}se>p=~#lUx7DRwH&cs!G=4)pQ! zSs%bKsUG{A)+4yCeyso|s;1Q)v-oEXO>5l)c!9 zy+EhDg>X?qY^>5+9@K?@D1Oppbzdf16wx@H?A^@irMXl_HdPZ3RW=&bE)J+sA>aeA1&+?s*w~PjA9)%DPqga6yf**Ng@I0QTzn%ifQ)awDdV%G zVh;wZ9jJ61h;dw~Jp@A?S0^ECpBM0_?Y&zQxiF!NC{j8oZ$QU!-zMm3h-FXxhoV1-a7udC$NlBOU{%8YWqS=_9a&OO*Rx5u(5mKZmyGE~?5&VH3WsMr2V&RKwy z*#)`+RE~F^j^ac<$}ipF)@&inl&j-u`96AiS~s&dEOf2jW1m}Yc20i(Rykh3mxl`j zzxgc;h$niBoY!6Rs0&wE5$AAlb3eMl;0#l!%$UJ4|v2FA}^Bi(eqpkr6vnI{lC zn~4~X4TN5tggl#UP;`AZO*gP@Qbl?1Sqgurfe7CD(Oh`pM4FdIt?p7kvbVdaT47MiCaqBdng2 znANz#MZtjU03jJrbocriom{Iwbf$L+FbiiMZhOmDU%tM0&;F!I<=Ew|Y(LzBQ5JmO zi4aCA%-&+xZP7Flx1$IO5wEXBPpXJuK}{FoTX5#0En<5^q4SWQn<~QjT zv~Vb?g}>JX9Xbj(I9Dnqidoz^I@xDJID z8n2Oa{lnWBoHH3BtQGP3O8Qy@W!F>68~Bk(rE)FwL#Ii#rgi*1u%Y^Jck6K4ch~)m zh8Zb!R#7SCzxH4Em;L{eLwkCcXe%GN|M_X9yuYZ@OcW}ZOv0*uf>@u#Owd!G#GLW< zD5CX$C4Lw6#WfH37PbC^4_Ksm+$(|azlBf{-}oR0&)B1<`R0kKh$Rw38xb+Zw~#Ev z-?6#gx!%3G-o3t9-?PN$2)}pO>A5*!UfO9FCinX_M*rzWi~_hq-84p!M&*;Zi(k)a ziNzNkyiyTsB3>gIs#27PL@E!cN>S-Q6Jq^wN#NZOKXFs-k<=J*Z47jpj&}GwIu>&w zDr#iNTBqmafBKbQ|F__Q_$5erXN-Nt1ON3)>4zr$W&-17BU9)!Aw*2d-u|sSRYFWZ zT)?zILKw)5AR|Tbk0T}ww6U~bx+Cr^v%7zj1u8eyQ*%|8}H^>0u1(FO%2zdemI(|R0r6h#yc%kFZmFfXacmLg`- zNIOA|T(Ec5_+g#xY*d8W7Xs|4s4Og0grnbPyJh??`N#N)f9UvQG5;<-@u#?0M(PJ= zr26B;t@vB+V!XBuWg;OPid3aqB|8Hofz08xW!L^#o{A3&*svb|tArMo;8h&4t0-8+ z2Xu5A{mcJDXduo6N>I84TOO=zv#Q&8gvkEaJbY+DA9AGr{RJXf{p1?u??# zPw&is`R?DI?QxyoC5>j~NR)~vzn&R-p`Si8fAb`a24G8Ob6PKr7yr5?(f@l(aF_vi zF5R%}?m=kn?YTmam%Ze#%$-}`f{yhm1stIcZK3Ob^IU{fy>jRVlw5a+S#$>Eq^%Rs z$HK%x9B171M8vv2V^}PSVk)%!;jOxUR&~d&1rMGoAD8BN(W8@(C0B9pT*k{6VH;?^oM4PyQ435CsV?G*g4*Nf7OBTun>+eWiXidLowsbX;NdwucDHx`iiA^ z3@$$Sbk}##Wv<0H@0%{pLht4 z(`v71L%l+{&eB;A1D7gXCbCuMF5bk-z&ri+GRyldmD1rM$LhEyL3AEcZw_R?e$xm7 z)+LsosYU9Cg*)OZqzmx1cyS5{x>!*{ia4ueb52|Adzz1OcasL*0O4{&8&$mpVV)#5 z17{43-*2MR$Oq;!{c!gG^V+E@8$Hu|!dA+bmROx)F8P~XUmh$l@iJ+9R(|3O-__1N zoO_`ITjy5D(5%G2*RzQSNy!=Vq*Q#n!nG)!KBb>2A0Os!C7|~VoO6dBzuoJ9$ffri zDy~{cf#R8inHPt>^xo!)A3fgpTBtAAg@}Vg^hs~RCI3Z|5sz{odw9=lK17h5 z+hzaOYsRa=f1{UJgsm)F?yJKyFr~EQ+TKT~=t+u35236jrmLD$*3YKGd3b_7(>ltk zC}>(hk4=j=2TP6125G&gGfPGF2@5T-eiFS(l0S&J8LKl*mnc0n`Ih5iXZYur9x&CH z9z2#d&|1VC|6Dgg@^50c6w?w_ns6Uo6nli-1MI1Uf<7=ie|*z_TzNIdq6W*`$n>sG z{pGtTs9p5MW8XyH%jX=FpB(z+H$NIsV(ob^_)tBKCx>zB+(-g>isH21%Q#s~7mlzF z*r5RV5{tXw{IH>n(tt(`;Ban9Ar*S2^GW$!$T^GXvh-nLY7%#YE37B1+-KkTHxavS z@U6k*UeED2U z*qIs_&C}(6Sq}Gh8;BG!?(hp>Jaq}jbAQmayS0sbiH>u-*!}$w$%D0VmblwvP+Akg zt(`~qr?`eOAJ|gCH+%St@RHupq^z-85qh>rfkBgeQ|s^t6a42>_S?c6HBsC0oHARw zgCB$tQ&Wp)Bw~Qx1`-JVih;RvYo}#D95#?wFco?;@=JKztuV-(Cl!Uo#hdx1j z?^)SR=YF$|F>>wVBui@s?oYQpfbFk}Hb0Y#N9DKi!o{0;^XEIZDrq{v_3q))!X~o+t>(^Mn^uvqx?1`v(Pi= zgZJv&Oa9rodY`7-?Hh?-CQm)O=>Y&0T8-KdZv2Pu{X?hyo3&?lb9ar`=c_}w{D+k? zv@u@qtzDBpupE)Yp9SMmtHSR8_O7*1UkFen`tK!AO-1B%tC3Jg z1g%^752=VdVlyig4Dq{8oh6(@+2>OPcGWrx9$cXq5sJGt0MS-DtvwYBTmi8q(nqj3`U}UOoCD^swGOJuhUy)&sL z75?bjrun+lXS7W&5@vvS#=LddXmjfnT}L59auxo@_g0B2ME@oy8XaL`; zfA}rnQ9m|LOEUS%2lI}7pqFHKCQ8f?pQSHTm%$GAPwg)>;V_Kc zLlc)Q-iq{m^wAQ@mNFArk&vt;9)@x`8O9p|CPNbmB9)AbY+9s|Ct|n%Bq~CSQt?&3 z7(o{c%E=n1;IzqFDfna3QqN%}#mx#1a@x>^v^>3iB*6z7jcy^u=AlC?cc8WKc3Hj z{THJKfNjP(Esg)l(!mA?44B z6bQvXmhz0hyY^HE>SZv`X3Mcw{M9{i~oO9@@IYc z|EA>M?8N^!CI4pk|Gz2u^Qi$8sI*ZDmQ;75E>U!LcQ6Rjzvc_5bNF7o(2BYG4*=y~ zjX%-7URIvGFmfR&5LUj|>?!PnDjzP7WvM*~8_f89JCY1D6ftR{spieol|$KbI&FMp z&Hqh(|N7N`wTk{`BwFw7!nHiwL|;U9v2LLM`T_s;>lS7Ht=Q3KUuDvLwCk_U`}v4u z8p5CTWqK|x50sdElJ{Z!`twejh^g4(k<{SXF^A(2fX}ur3Ms;OM26S-vRe=Y5$4hrhe}uG%zFx(@kU zvYN-!q?{j>LsF-MewS%GQ|}^bWLtX#Wwyp^g^DMVC$K0qk66u-(VxZ=86Qy7l~X88 zT9o7ttLtKE1J5r?LgeBqRTTvNaO(>Ox>I=bl5d`AMm zyEJoOrA&U+x*z@C2M`keOIgIN2`#w%TTPu?`P4xCJ)Q(%B~KM{w!yn-`TJn%uL>G^ zBSDi#%z$!VyJmk2M~7}FR?{%lJk7l@vWU^QjAw|HLf582`vS-I!~CG8VMtE8JMR)? z)FGtH3fg`80 z8xTp2_SmOne?1bvJ=T9iG8QQQos5x^@vFBbFRM#OEbVk4ZZV`g=(HK0KY2rb%{w@Vf0!c|BUWSS!9qCVMMzXi!JHswk$cruAA#oKw$ zkj1~%i!ux>E&NeYjSL{w~)1tMH6Ce&0{0)e-6;9b1bB008pZ-a@BIUd-X~mq3jr z3!Lyite@RxNb3|hV`7DJyG-tT3UrXsiW_ZTLuyw16xsCUI8V zf&bfP{bmqBIxIxhkk)slfFsf?)T{n`6XT2fRHc^vfO_HS&7#1+HH5W}>R`;e zM}kf9CJJguka#k-R6_!e6#e)K(GH3WN3~C#!q5J4jDE(q24z;l(NFRc;0JwluHOYb zsP;n{@Cya^LDmxnA8koga9AIB-)XxR-atYix)-jeZc?Vm7gRoMz@*O$%9q^EL-}S4 zDle|v)oq)-^*K$|G8RW@`5Z5p><>c8YuD@4oYsa|%*A*J;us05pMU@2b}+g$J2-3* z-XnU>EPA}xpTKW#Obc;h<#MuM7I9k9@+{ynnG59$KG+x^CX<+23KzMMsyklPb#51O zvYE67&7e265_hkCr@-H|YODxJb zW<6=-nrHiYbO?%8gtw2Pw?{`xwq;kH!zuYh!O*$LwDfoKY^gqz z)5qNvedX4}5|fYPiE0dnW%VJ+*@dGL<8<+Q#Ok@$0>c%D;RkQQeVap!HQO!8a~-nL zR^;+7am&+UKqfMMh5EG#e0ByC9%~!h>yABHMM3!Ff?rEJSa0W~x;WH}ItzB&8-XFi z_QR8|uv&QCZMg5&6WZZ#TLYfYLU~@pw!Sx+ln-hYJW~%AH&s_x7f$nF^E&!2vvN3? z5Z?0js7Fk>OSgxV+ro%h#Pp#})%VMh`BvkgDQnfyTugTJCP_{m*Ek;E#0?YGVedlQ zXhq(zf{L-yn!E1G8zr9SkPW3oP96%+_3b@=E;!_#TDBBo;OvURByNqE3 ztB}G#7B%Vt%5Z+FH21|(!O0ZIgGBpQYRqAQi)|Ps%&@3VFv@81?M<%L7<0-I+e-bp zqq#6eOpLOQ;8Da*2isgSq%f_rtw&jyT1nx&sP_QwD@N?OS*|?AIIQRRbiJ-W%(>Rr{Iyr^C0Yn4RhiV{sZUcE4km)fSZ--eo`f zIu|~KLqdJKZZBl$C}% z_6Uhx=upKZeNudpxOB0&?nG7HyXLvlY;ID$5ZB>aYDoGBnD3QFHeOwt4wAa(GKLN zA-4t|(xIZa(*SEr?7~3zbIc8J%c|JSg#ZFyr~hg-t#gNMP8Q0~p~U~aN^k+xItQ~< zOk{U&clxgr>b~>Sz7{BaJa5>1*Z|cPypgz)**jM;eqpF*e@y2tDH9;^MmB>}z_5Wu zyJQn~=b-1dO2;s(Ktnqt6AW+IFj=S1p?bhzv!Hi`6}lc(b@BSP<7?{ZDF+Oi=vZ2U zi?%0tI1*;z%kOd79%5`9bc*T?Tuhz54V0lc*6ik$Rbj(kCmK@{*x##KFJ;=%ICkqi zb=JU8lt_n>c}h%p!oA(c7nmMOJl8ZlAAZ4POI%~1D@b_UD|y%)?&~E!bttWd8Yw#i zm+^$(Zab}})-9Er*LOV^aZdGRvfGycz>cm*-*r+1ZrwJ%g1{-P+1WYTbal;DFQ`V1 zbe;CLJDZPavPy-#6KcaLb)DR=JX&OgaDNK&08Du?pssLV3X%V;Q^1PRFtW#!q7RNY z@NiG@7`y3yUj}-fz6@qT7VJn+S9S4@b8pto9q8=iVsuuFnyn>pTdLL_jIEWA4OEt0 zoUApAxK2kpX0=MZYXVPTp6<<+atho~7Hp42ToU?J zQ%stos@e9V{kEK;Rp>}6?N$=H;qBT<_oYeugilPFT^d>uO-#TA}A`gd{;v%KJy*ZQe7VF*k#N zewRPm;Gq%Ea0eV*@~|fSr`>pOCu)czl>?ZtkZUwR>@I03L+&n>;<4H`$QAMGa`YhC zuC220g#|5B+u#HaMyJ&f)4}nmdFs_S6erPwT{r>wyBIVKN-3mk1yK8FG~G6%D5BXk zpVbmA;~=`=Te_+3+L%_akJ3ChkB>GFeInE|?Q1KiedIqAUB}%Q^gh|sdeVHx^qmf3 za4~~9-80&ZN$Ev;+onpkyL8^@po*APF9An#lSo-)-)V}s`No82Pije@^z9)_)nyOc z6>-zl&rivLFn2y?hBJ}cbP6iIbae#hqjxsRx z9>|i!3leHiuU1yK#K1@BlWoXcb2J7%U8PcSM|uW62I(I%{(pr&|HWiH!1|OeZn{$% zm7!HK9?Zl{*}+pPvxB0|z4H~;gQV*T$&PSfD-Ts}e44|z-ze7{ z%+;{4ab`3pZ$+ocQA{RIwrx;BY;jZvmjTR0; z!nJJ0bYdjh`CJ1%I_{Y@7ZVcI&l&J#IrL5#KeJu`q#6@kJrJ>_F;*ml}%f_lPuM?KPE+RX1GA1QhgHUX7y>O33nd#0A+Id$w_3)Xnm zzWp9l?hSRcob1eQ1@L-?7ppOK_dlEZM7uxh)VQmXtVaT`7h)82T2{$ft3SMXHC%Y7 zNDvl{CU)F*e>>T+JC9W!HLRnk*kRwNkU^H}u=S4bEqOK(+NfA%L!aYV{^c1-+{;?Z zC(S|jU$D!UN_zKoy2VX757+W*U6`xqqd1=K%7) z>is^XYZr?XiXYSmue*-KDM)WJxNw{XOl7n+8#X))j5F${Z?itxO-GP271gOaAIngB z-w;|qnylLeb~(8v)pf!^Ura#8Y}_QAa-lw4-|0I>$x@o9X`VDFF3L-1P;LoF2y0L_ zXcU<6xJDhquo=jb4|>Ra_xgNc24Z7;Wx7k-n$WWcWUhMO*)39~L44Y~4%DVgY5g~{ z>Ysa;-W1djNvfSrE~Str0x@p3xz@-`;}Dk0Hr#9WtwoY?_aCFzfR`V zA97dF@KDh3>YSqRTBclyr7H_JKZrJ(h5NV~nDL!!S=b~7LoWtpbGKH%_fQ7q`(8uqmh|e#ssi!}97V?Z<@aLE-9j4)=cOT2%8OQsPc`q3Y}Tw5hLO9D zG-#v-;F7dh=A_?@*LQhPFgGeR>fg!+J>x9TTknn(Ueqb)s`bf+3c>4y@I~@ndIi+t z^63Sv=93dAb;1K)Ov+L@6xAQ(t3wyNO~S>l!YDkwx??q?)v2S`svMWPd6GY*r*D;| z=b&Xe?9*uI*$23-w!z-3<{6dl`g zJKABJ!i~0^w6IB+Qx6{4y5JnlJIZmeFB_f4I_(bjx{_R|{kIRua-*1|mSCoAjSe!s zGP(WTUEjkukGGBq22Xj?ZK|6Ww=1EOI=c}|=va^a0PMq1ctQR1{M8(QH_%df4SQYJ z`cQ|$d5wpMa9=1(#fVo~ojQOeQPPJK-ZD0I+tTji)4m8a`$m7UHr+Ju3uDwsHt3Gr zdT|r0`)MKDTaCLT@lGd5kXy5suQuuXu7vJ$L!TXjVTsWx5&yzro6f%Frn$L`waCS4 zJT!1FOelM(WIgqCvsMgWcsXLdY2`fGu0|A0az!}A4Z0Sq_}QNC4~JlGLUS}oa?)I+ z^*mM<%EO+zluEvnCA7=^++iBLCJchozR3K%M7v~Rce(t!cB|vyxljE{VRyid1Xizr zD~-dK+N|4EvhN!7?GidL#$|<`6|JZ|YjEiiK9|a`+mSmC?)P7zewB(1LrZD%%jd%(=hVlTP{a4Ri8n z!LHk+vnDJ|$i~pSu6HDg-T0au^Cu#!bij_q22^-`F8I)uj@W~Z08@p-)1w>5pZ{sc z%KhaNcmo$>IgL^J>VfPQ;4L|jS_epw%yJF<6wqpse^9_Q=mq=hcT8?v50FE|GlPF+J= z008uDoqflR{F<>XB)wJmo_}ebYc4{v0iTB$2hR*dJYXt4|H=o$rFB;@cV&A=zGs0M z;{H68XSnV5{K))s0gzzk<1U7Kpf?vu99!-k#$aRwd_r*=Nf zyh=Y8E`(mRq&PR6PU_F*F+mLqO8>P<$}i{;ezhIWP>8Gl9bDgOkev*t==8>b(>Gt>L04ce_QG>Z$f#@QO?0dnxeOi*nqhtO)Q1{ht-CjVgTM7TphI^0s0rRvRB51w zX4Zz?P&OI1J!W0BBs>hD3<<;e?AO&&5QeUc&$~m<_0PT&kUXv|IHtu;n{tKg^AId} zHS~8+hX7!F&wRAU$HnVxc1aAv%4B9U7-}Uv3WCJh1x70hxboC9~RYP=?7eFsOwj0k6ACvIxdywIT>01Eq_K&Sa ztM}t>n*gIy=>Ac*=kR>nXM3wDe11K1k!&G<3;Gg?J*UJ?8pP+t5XTS69M`ekCA$K; z<01KgA83=yi8tIH=0D$Sff87SX;PJDzg|LTlmWcA!{V2RzbD@Q>5Gi3z$lgXh5d@Q ztSCE6;`0{|k4zB3AYZz8_xwZ!urV&A8*3Wn>9$pU+1nSVlmnti(E9aQybx@1`X{Zl zHxjL_Tdn+LYi%#=YTb6bDjl4!D&EvB#CJX3EZjcZWt(TT+9?6i3VZi?*J$XbIq2Rh z85&z#&|`6I^h4nQEPxciuJ2XuvS~+hX(yH~9;}!3{KEZoNtUPiZe1)d4?;8xOh$#w zQ=OIc-1?eF-}Ij*+mzZ*cn?oQkn8|nH9eyMp?mM=H!byti};V>72}2WqgmCVdG@Nx zIQ0#B{;g`tLU&l}_tuE`tq%rAmH;!50!Z2Qx{kx$%SE@jH2hmzK3Ym-mCs(L2n0gHRk13~ zlSbxpqzs&^Ly=D6Th|Vj%8!p~t8#Sh%Ac~pW_5hkYkPx}+g1aa@{7Hg%hquOYP%~> zR**3Dwr!nuH*eeLr8IBGhV4+I-8cq}fQf^V^EdX}%_JI?Y=Dfc7|V;S3-i(~{W3E{ z-Lc4|RH=CKvATR7ClY$LP&C&LDa>_0SzW@z2E*}%=`;+Umap=TDwm>xIhUcqU6mvB zwL0DBv_|K^$}znzYVZIkdX#_0@1^6AJU*`sxT|=rF#Ni*@IAPIH8JhykwHy_OFoB} zo5x^>V^2rDYN5EPB2N$Y<1m1B7CHkWe;)1J0d;Cn3Eg6&`|HJXtPctz;$CeTczsVK z<$rEuaEwH$ean4_(2Mhv1zSX)3}v&&nq5le*>AwSrY@oPduI5B(7{Px!=PrI2FAozRgEhMZq-6b=d#GB1WXYPlBxyI%b+Z_ z??%fs{j|ckCC*Z9cRLSK6cnv=;@l-U*mDT7kX6fHaPtm3_Gt}|*s#2Uh>8TDC%H`H%sd zS!Y6|+8*He!y!f0ydX_jtYY*LxF0_hwAp~A^suRV&*2r&@f@@=NWB}%WVyA%Kq(#1 zs-HJbd|OZt#1+O!{J3E)dXv{iOZc=ix?JN`M@$b0jc(hOx=&Rw6;??IBPRM2S65)h zFb#;kRZasDRvB8t=!RYWenr)O1@ytRsP}t2XhUC-9TZ8E?a3B&R|2}Sg-=tPu2#11 z6q$@jaUK#77^i~}E+%!D5_OsKba{;fmad~}aqR3JOoF;OGfb2=9wW7hU%I;GVjX>N*vw$UFJI zdwag|WUYvVV8T}!P_Q$=P2Ok|VI8I?Oq6ftK>fYb^Ph7ozmlcg_mM~`I%4uA!PM|a z&GA~zqGd3~s=ESuHrQsr5UaVwEU&@ubynh=r76*=X%5OZ=Dzz1gG)|9=VY5~G}X{F z!o|9P2vzLV#%BGXNo4l?P^?v;aDL`l?Z&NmeGmJB9b?Hiz9;47ff)B@ z+;>hA1*UNOT;Eq~$!)Q5P*eYE?Ru%BS!G}NegLndvsW7(N%N-I1dHaQlM!6DI#MC{ z&UxK}?DPG?+6&^2E95#5rP5N1(k~VbwjC_I;n1wY+9X|&^Sq+%p@oE63??Gydurdh zW!VqX!-cOQ(}}bwQxdw>fbt#Tov`SC0nhz95Ab3zg^0&vXw0Kb>1G0#@v^C5O$92> z>EMiXuM5y59tWbVaJn#Lo;ttmU<~ODNx?7&VZ<43 zE|F+a$68|kx8s&Iwj7Nw>nWAf#yCj0zJD^X4nIGf>aLcs$nFNM`uz}lVjLKK(UWQK z!!ROEEz!KZMcACO@Xf<1U4G$|{Jn(yqlEfFl3SevJ(aUhvxQGfuAxRk5$BY1l}iXw zPmA({>m3D^W1Kt;^~RmB^m)9SLsl_kZ6Nq>I5k*tZ!L^pXMpb`BT-}(!0Ifm(b2A9 z$_*1(7(_H~O}2rEMp@{*vuZx7!+}SZ@;0aG^OHI-A_XKhkxaHW2^$4V}Mo>v)7tQMtt)bpd!W<|1g>&z9`?fwD5BiG>8_a1M&8F^& zj+h1hP}f|&z2y}?8wd{fa1!tY>?BuHyoYYuFTWGZRV(K(>DV;AI6E#`BXCiELsr&t ztJZfYF$V^!sJ@LXI*;i)@AKGylXY&YbY{%P_kw#)hcY3O#JHL`NbLzm2X&py!#gEAa=_m!FF+242(mHJ59C2=w(TsFg@b%uKT zV7U)(=Xzjg+cK4ZDY6;b8|TXJsQMqjNTMm`$E1PR?QZh#72ny}5jmcRnhe_cl+_4p z-?W`m$6wZ7!iDAQ9KNZ97L+ouUM{+H%rc0G^r5P|+wn;0ed0Z19)>(?nK?1g$CT z+QDRHvGBn+MS~fvQ7XpQlx$juA_nnpe^b6TrTE2DmXvLn*L8DZ#I&Df*I=o7%ruPd z{-hV=jfMmj=glRM8@~RA%)`yBmCmyhUy2@5cd_-xGcF&YAOnOdt72c)Rnh*K>8J{s zmPI?9R?}zD=HaStkgLX)ic?iHM3-X#8G1o^k)N+iyopXcEIz-t(rozm1heB1#$EFQzIn{tLs_u24PoE$rD^J9Ln27K$fZqP$aE)FW8A!6sp?>pbUr+kBV zo0xCnxne^K2&HBdl$u18DS}+G>M? zI!hzybdC}cQ*>JQ|5*F$sI1qm4H#V_Eu8{NcS=ZicQ;bfE!`m9-QC^YA=2I5-Q9V9 zxRz_L^`3pk`Suu}|M)Nl`rI*lUiUS7qySt6^O-@95J22`K5f)LYh}x--Qhh6oyKK0 z*&pkCRAcaJImYs&PQIu!-OZNNEdwKkT)+Hqdqpgr<-L2BE|)Cr0FDF~j`@_NArKl{ ztTd_Zi;cF|+jJ4;>)x!;A*?@&9V=I!ubC`Y-#qm2K;X=i0};n8O~Ym-^U)=}No#QP zh!o4#jOAp6&@aeGnGlfTAu%kzeD@mX*>6snArxXZ6w2_0fuVYRq(y;(-ZGOy=pY<{iC z;JAHKKWTk94qHimd3Z(Wus#t}Kw(?;{;+I+e&_;xt4dz;wuh`YT$I*iN!=ovlBTu# z@~M*5@SC^bKnv^`2Y?9)Q38;-A?-~Ujlc>$`(~h}Evy*Sd>5;>@!H6sF0D%Qo`+-I zZC7^M!?W!db=2yQE~psqFG4#!4`nkC8)90h)=F{lnaGt00?>O*r9jCMaLV$n#(NtC zf`?cS$5r-(+Dl*SUVBO{kHoxQ8%|gAaLSaPhJ6huMvRb0U9*F{_qoki;C4CI|o38BOeN{;*(EelPvOE zrSzbS3Jce-7hbRp^14|8qPoE~)i4pm3t(|#WwJ?&VsUD2IjUO;AOCz~6$6lAsHj|M zGyKmW4e4y|95DQ#4{lvb7KXTV7rc?*#}+KYLUn7pRYbm7C+Nwpwd7=3??@()Q(eag zuT97^TRq;6Ola4Gy+a3>3_iYM4)(ORN97?afg_}1Oud(ko^^dZBcXl17?IP#PSeP# zQky9)ID->`z=eSOpxk0*;OZKa>GCs#F$Bv}wPJXx4GV1=ds;fLhkco}7)V=`SM# zIkk$s!cf@r(?iY)i5CP-45xeROl&bjLi0&acK7|=j%Md0SV8U6eOI`A_-#^Av23|n zE9XZN?sU4>oL>h!*z zNi!HI!`$*iP`hroRB*BX_mDcJb@Q?ZS#Vm9h}t|BL%0x^(*q%hYv7l03Vbu?SSVE7p9m z80uU9#2}~314(^O zvaj)(s=WLEtcjzU!0Ltu0Irhe)~#b#0L4+Ucuw)z@cn}MgS+KYjgml~WD2IdCV(&m z&RN!OH?H2-(Ejrc0CdT9Qp8Y@;e&ue}-T{Sc6I5e%NvcVsj7=boc9QL?z zQ3)nciRCS>-Di3Qpz8Dy#Zlf!r=rYY^vys}L&WTHzzA}AMw$!hmr7dTt(gdR=Y zY*GWC;^>y5c5#oMIZdDDyzq)U<6)OpiP{qrVGp-5Vw4M9CM9@U)@Zx6m7}X~V6)4l|!$KRs zK4`r@cY>3tDzOQvQD5g%#~N6v(m26%agc`NzK^mm;Kxf@CYPq$&ga3KE35Q7*^2cN zCEyA3k66v(=pGYDq+ac}lQ$+&W(AWs1ZFv?q&u!H)n(bw0L|F}ldRWY3m!!Se21DA z8t|a*0Y^go#n|RtOeKZYR@hY}lg~!{DS{MApjM1Z$l^h?o#t_}1t}8sebngMu1w-nzIJUv2&SPy3+B2zQrT*>xoOyke!%-LXu@=6kLl`lsdJ|1 zP4~VP<0u;K>%%bt$jbUX#iYO11@OR~`y64=@8o(#^x2a~;=oYPgn^@T+@hJUUKqcE zYdyN8)3-TTt_12X?PC%TQj-@aa&w>K9+{imy=Z*Vlj53ZUx~T~iAE!Du3{YpYDVx8 zR2F_>|0SmBB|ue(@nX>J_AKtKubym=3skQoJON=-iKUkiVQ$dNP+-ZOR$I`i+6(;J zR3OWIIV1PEHEtd)2VHy6n_wqLQ9n81K8y?Cw+PjXJ4UB~!5S_0Ivp?>>MyeXFIpYs z!(FP0S9Xc&9vNeoE1nXQnzlIrFhkgDP;U1J{niNi!1m(FuxsMAc-@1AyrvlZD&p>) zDN2MU;1yL7_Z6^Ry*js+rWlu;-pvP*D7h6M(N@B(mDM5E7*>*BECN()pNCvEE#{Oi zuI7L?OYQ0JXX~S}uPrl6yA^=(M_kfXCewZ&o?E@iM*QWg&G~>2Nci0t82-hAu4v?U z0H&DC<<3J`#3(8C)RX2`@N!x;4*iy1LG*q%Zbr1f;P;che@VS8$Y*z-W?7}j1VH6o zSoHKMg`cRV(P`Cd|8he>C0w^PeEvV7Bps z(90wT%bnyGvf52H>8SA+aLwJ7)to=3AUqVw0W)-tJo5#(Pj@2CG#T7;lXoM(Rme;Q za48A;H(s>JI_ud9V`Z8*yWFr_DG%0B-gg8EM(!JGZI{*~k3|wD>(0=M-9m9?8O?7OVkO3j^$Oz!g zONiO7FN@oWaj^xun^ya5Out2R3((D^A5O-`U9B_A_k^(@CfTlfZin|`@RHUT%qqn^ zde`$l-w|D@02f5By?&{zQryR(r)rJ*K=pX<2#4bL&wc$iG=^v%`+%l}qq^tjxZQrjh?>Gn(rdK+ zO@U|_&Am;pQ|V-XqM?p8C8TDwd10)UAX4VVeSk{3#WBZGa-{(wD49M9EG`Gl%)vdU zxs2(tct}nTh*-W{{r+$A82}fKG$MQsk;o(z62kM=S)i^oW&B4kQd*{jJqf~G{hoUK zeatzFb>Vu@BzZ)UyR~rC%SM={hRGtk;eVrP;@$u?eu8!cE54=I9v_USch&%&aB?(K zZx_LTHW#eH|7(BI8d{RZs3&A{`T{fNDZr&%lRiPI%7k&2)n@k5$%B~5r{AY0-@7dW z^3AxXAbD#gc<(Ir47*Gy7y?xd1+4m9LWk_+V9Oa*Gerfra*=-Z@wbA;0ze(gii_Qw zR(}=iZGpDQI6_uCaYaAMGpKn7dyt5bq*dS%Xq4Q`841+7+Xa>wV`&rJIIBj%d?p@M1QcX|DGIou zxDy2zTm66Y!l?pO7nPmEG%e4THYdw0PFIKPVn`w7sQ#v)^Dl{nFSrt(!N4rRpsN|o z>Dy3Qs;6_+s9Of&-*WVim=(ZZOttZ9yrFn@VKo<}R0a6bjMw8>v3{fj6h(g?9`_rM zO|kQ%`MRJCuLrdJsp}vY4YLR9LsTR~SdhI{S>u}TdcF+Lsm-KU6sNDmS`ki{7N^sn z4!VW^dfiahx-4d?S$6V)N(Oj0`G3Q$fSuL3IIdu#`y2n`0vc0*f(>z5@s;GzQsc7; zjkqfd2^61XG6MmliiJ<2fB@GE<<-H?yQh1{F>}nnPx~JqMjbo`%fgj90=d#$7+Icp zT`;Q7E((Z#n;sTWI?YH;{XMs#G1sEKiJd7$dIfONbcuJ-`>BVi)44RrG@;xwAPEnF zZGEU+ik1BsFVoK|Y5<9AoOkGNtwaTgKULQE9FJq*bw+7{=X$QL0%2y4B@4 zRh;tpbspeT-Uteq(8;omEmM)7v~FuwM2YMF+pzxQL$oyR-M9o%@$JSyJW;az-%NO- zq@#+h*-P?BX-Y}t`5bRRau7(TUKJUoDgz$Gj1SjZ6Vab?#6|z{m2UIoKXjX2KxY#)r2lF72 z`L_xChm3sZzIZ3!A7}m;Qhm2G|2Hrt1TjB)Bq#*KnQY;j2kovD%kD@e?QqGl?3FMxy;F=?XkOuRx1DqOEQ)l$tPbadQ4;o zBMJ+_XwL>PDvmJ+&?br{)!hw?`PTo77QO+Y!j&e|Y&>HcM~gSj`@Loc-gH?`8pf}? zL}u$3#v&}X081GGn5eCkos`KYsG(pwEVS-1#jAf>3~mD!`1l__)O2RRjI1~Bmrx<7 z(8&CN28jT3+^0hEFOC!bGiCcfIz+CVF57AYTpOxO#Cyy?WvpBoIIf*8D=E*BqOH_7 zJ0#q=h`+9F=!zepmiTpPgZ|ZrI^6(;t=>{f$nTw{ze-Pt^}qs9H>Q#Bf(FIM>Wr=f zE=~gz>>twdx2#u#c!=JOhtTNMdIohN{MiKb=#qWid@R<=&eWe&lHriQBzxNlpBtAT zyrB%B>)}_urUmX~uJU;J?{}1=uRHH<*fIlH)8cY@z<{vgYrmQZu#ymv{}w%{dT{5s z>~+V{s{QEt>i_5R+P{)Xlck{#gq&O$HyE_vK_Li({yKJR4n%<0s&`Qd;BmsIdWb(m z_cv9sH~5<%!SGezHx|!pk^Be6CelGXdckS8N&u)P(B=GXhkl>ZtB)<={_EIFR=?8n z|G7M^3Y1rY-0Hq@tohUQ6N2P4k~HNtqyjvbkiTvmBO=yy@b(>lZE;i8-|Y#8S822~ zcT|Jo-_9|T_Tbj_ia%F;T}jsOl=Pps?xFan%;^m(eyezo|NG9Nf8F`UL$m5J#y2+* zP^3Rq;foX~Kwm|7g9?-qg$FoaHC1hT=|AZaCeSRIW3Fok=4M}vGvos+;SqPFcwLFi zKfm<%A#hV5H1@;tf$8^t(GWkKQ5+spt<4y*)0ZdvqoB`E*=(%)Aw3JprWCC1bmJO@pU z#`jlRfhGoMK(n&BOPbQ3Y>3?W(uK~I&WQ&Be|Q9QZ@1zjBp@2i^}MS2KqK4VWOhJA z0w~u`Y+VeXT#4YQz)JkdEQnrL0{z>@|9wip2SYGmlQ~$L-KJpZL3n???hncVG(h9g z{kjxH(s(1p&CDpHzP2kvda*?LjMtL%nA)$2?ZdHMeG~8}j!(?P3We-=^!epNKVi|7 zdTya*;P@!!?zTcizcr#+oY=ar*-;y|6|>Cu3RQZm3CpAIgmd&F&SGyU3I1~JC)XvH zJ^Fj`=d_AjNW|83;Rt|GoD`94T?x@sQ)(oG$bh~3JCNYpYOcfcv@f}fe1!mfwI_v2xK0Jp6UYrFmDWH zkp%ps+ohZS`la-L|C@jO$X(CZu136+-xt4Dx|a`4@t^>LaBErRBLUT?oyXxg_;#L1Y>2S zyt=cCN+9mQlCT~X3jWVxO7YSmBTCm$i|gtT@YC9!xqC{vvOczPWU_@VkEZk-z7Q-7 zba+<~$aW}4kZKi^fd{^N{ZkNM9Z7sI~Si8snb(Jr}{C_w#dKfIpb>w?kwWbG*?^3Mum3=5l^ zp*-5K+4E*BmYwBd#1GDGvuXC49LB^qxO^as?scc~T%k*d9#gYO9*CyO5CYr;5b=L* zry|}`0H?NECaUnyTTVy#2Kz?9-v+i!tL0}R0@V0M=TV)})tU2;X$8Cd_zN}TE9E4Z{+GCIrNKpLWcwfftzImbE9Oq z+tu^5#KUnpYYfMt`{O8%qT8%w|NYJXbQJB~^`jg^$I&xRm$6w%Ir0q!95-jJry=bQIc- zRSN({Wj6aLgG35B*#mkd7V`hdxxFChvZiTOj+_HkQQii~9LqcWxI zhtjWxa^BSuAN6W}PW7Bjf2E&-}Zj$@Q4+9B2NB9<)L=kC63ns#o z?7foi;aXoN)UN3B4@La10)qk)OR!26Wj?7ZK0tFslC)N3FtWElWfDy!Mtl!EZt5U{ zqtR&2mdWawXnT1ECg~_;2V;!;4O~daz;S>mm43M*L;e0rx9~e>5yIm1nJ!*nS`8Fcx31wlB zxVo^5a#mEX#?C=`R#_-@oy#e4WuQHm*<5s3ehAnb-fYMSZEG&&sWLx_qqkxT-o4zE zlc|48KVWk_Ug&<^z!dB|Uc%mR+b8O9_wOOI%6L6>la2Kk#$nPi$>m3kB`n&2$S2`K z4_)*j5NG$66Y}4eHvEXjdrN7AC>?Yt!`VRO*bph=K*aC4I9scZ?)3b~Lc&mcYQ(!W z5NEkRIa9jC9rcuJ{Z$tjoN72N&K1JGClB5)@|Pa|ZT z?ijl|SlqzFMp%-3?HANkYCd0^YKO58aTlk)pgKJgnF;he=Y@yMH3{q8ut@@VEpOgs zu|A%-zhu36>pOaZPD3gbYAWBNsz*@w4b|?s!-B#7m{()R7k2-g6B6QNxg{$tC@u$> zj50CO6*#&(#<%38Vd(7sj8XsI^qY@|4ZGn z`)d0WxBHN*ryUgy2k_27)SyUWkwJ9$68Qp8L z8MkL`^i~Sm+TPsC`Q<9Mg=v+ENeZr&F|LXGBgMvZ4yz%ve10!C-No*cpm*?%bIRQ961<23ssCax?;(Nmo*>Y3=s2%rC|fJWk1hklzz#t~>&stENL7aok=S z2c%*Q^=(9@LD`$?Br?H{SQ<6JeV6``?}GZ<5&vGwzq|qphz8&n#2YKD=yK^tJ(*_; zZG{>gFJcRvqe&x-F7vgcnNGrTIbXK?_vrN}ZqM8vQJBn?`+742TAppYM|k#t_?rFJl$yaClfKzAO~^4Vb1nsZ8c?; zs|R0B)T$e#US$X9~{QWl< zz{{1lXX(_&)S@G_k+)!;WGqVxt7ABF+ek_ica1UAWaQRBQc|usM%hO{JBT2{n|+S& z1{X(lE2E)DSYL+EPug%~GCJA}_Y})i#R0yV(abY*uWj`;+bUM=!vq;!35hFAOZ#|K^UKr4+%L}DyE2ZR~ z5)2c%)et&q)Ehep2>AWEm79eUXhBl<mn@}>9iDbImA9B8L z@8)@VXR<1P_Ya|Y+(EbvPLTnha)D1)#Yw-E-^X>ar|EF+Hh==t=V1D)=jRnA;zcxy&Su2R`^wcV1SWd4^5mp4jDFbclp6}-6K zkcacu{*q}8?TRL$k|Fy_@Y>Ym34b{S2TTux5zWyMtU6M@`$-oC6REhe{tI>x=Np_1 zWRek?PJd0A3u4<_oR`!xA99)hW4?h{fp|%o1w)RLE9>bk1bkGOlo}Our%*nRXYj@D zNsoBnVg1LoT(P)o`8+$=p%=M1s4#Eg{GO?Nm9(goKy(_>EI~LZ`?w;h6`o+w%Fr3- zmF1Ez71WC<-boaX1&H_nzkn2xn8GID(x(R*ERJpJaA7KWa|cV2+e08Da5!Dk-Nf%; zyfFRx3BM0R~ z1!e!Nu~=aZe|0#QmRix}s4WnL@-^uEnY+PiJDtHu?yOwwS!s9n3^`cYDyB#X{}Zd) z4=n?7ZEFag`8^`QBsO->hb&h@{#_|T-)?hv(nHTwm8YUOsFlhl$>WS5SLS9!)&1mqc)-xHF> zW=lY|`XqNu4+crGid%MHkt{_CnV@8U#w)qm?`?Ae0u=scinG+-2?-5Ha3HzlzwQ#& zgPArXH%y!%0y{2U0b`kb4IiT8K)|n9pqf<1st<-C zyE>g~W>AU(%ni3o{5(;sTJQgE;ApF;ZQ|}--0pl0)+HN(YO?{(N)(|aH&?c}WPw~x z`iD8XF@v-<+vz-`9;wtEvxS@Us2d~2xUW5d80H=hm$y(gds@zpUvS;cjpy_A>p9RB zEKdYifoZ=sm$ycZyY4a6m8c&yTU{hpNThf%#&dEH=jbXqi8JI#z8yDnrEofXxHUQW z951n^lw@s1OhM<*1H1uR$P$dB*J@nX(_vZ#NfzZv-zN*5;w??DQX(nsIsGz&VI&SjEK zm1!p73j}5py}dK+>i^8(P;Pb@=npH7M{C3^Ej%gN;hAzO?B8khaxud7*aAwN=*#qz zEzRXF=-gPTSUD8@@&t8R@(01y(vd}dSr^-!E&nsKLXykcACs+AC zn#+v6KYoz$U#DsVl>wBFoq0%WI%FutUbXx%!#OaM|MzQDiP?k8Fd_+KAo*=UF4t?HhHI zg$_v9Toqly7zR5cyqolPp#ljV#I?ioTQYa`Ci|ffDH6P67zs8ca`TjgTN@LSux?EM_6FE;F^L6ID zn(iN&$NC0u+TOQ*>ocBjwq@d~(Qf5{1Pwkl&gz!j*rc0u?}+z6q0kRLbt1cLb{v-@vX z<~YY$ZLT|dmC7_GPGE$TA1&JO!ogp}YR!K#s@7V0*@VPy8&u|ofWy`?j!TDR(d%iUt={Izy??j8Y#GQBh{Hwm@2Pa zs>bo6nXq102rknaN9gV4nstF6GvIw^a( zn}P}bvCaTF2bUf=GiJ;2$vdw1h#F84Yj?7gnyrE0Fx5}4dNt#64&4HpH&PJ@j%ytP zrEbuan3H9EA6cuXe3 z{?sv?;+*ds*2+_v@<|&7mHakJ-JxvxttY9(*NEZemPT15L3u9wV~`q?6#;_Apw6rP zsZ7a_Z>PQ^Qn$uH;h6HIVsjXi>J2AHJU?E*!D7=z!r^d|H%ZS|8yWVkvs~Woq%HUq zz4hV#205r%9#1o>+N5~3`b9lZNUeKNozn9F%KFAZhM2F`bj(||#uRO{`gjp)RT~N! zJf)Y@a$G)AV9!@>H82ebzLShlQpm$X#Ye5cU*kBeXSX>Yp0 znT_8p5DXT-R2LUL4cWMxS+)hgu95K;c4p^w-Gt)ZOcAmu*wtFVkuO>>$f$1zvTZZUl(Q%m5Ro7mXahl!I zN@aFljO=061#+?@=Cx1K2FBqYdHuAc^O3luX*@&X2nYlM!NPm-nHw_^_~SJPObz{6 zq>yF^W@EkEgPM|Tc1JUr>4W!AHzKJW4td8tMNc~yib|(T#ARnp1-VMPEJ4&e8)eLlCC@>||`*h|X#3Md=DrDRGAdnR; zxM}Uf<7(}}Zq*vi`BxeY<%gZ$Z-|LMS&xodHm6R#XDOv5=zEGgJP`^jFbVt7%)!^v zU~m5bWxVWG>N$yy#GAcnXPG*J@dE>zp;CeL=AA;RvM3z>U8@xY9+IojX0N7+UaO8R zl4}}dXSTq~vwFR8Hl%e70@(xG{ssTDanZl4*{d3_C7+O(DB6#Bj26%Mn6zIh?GqR* zVNglKM<$<+m)aO&dOdyIGW%o5LC?TwO>T}|ZSDtEfT7${x#G9cRM+RQdi}{BqR+C) zROZN+O9W`PNeqsdE&A@(1|z94(CF0Mz~6Z~JyPQV$a$oe>)z39_SF4PI+AAEP3SZl zqX1q9K!!}%q#|aWQZveR!+ZgQ@+NHIp)!29R%frbJ=jj}^x9Z)yVxNYt(bKVKp|`0 z;fE&p`UZ(r%)it>7OI@Z!mlq**H##uuU)V;Gk7uX*ZiVwc1LAcZSP^)Y8~KHDUD)Yz;uI1Us?;OifzVJ`W3~owxYmdFPlS6ShGjSt$V7 zma9Vlv`P5mxXCF6NUfw1*=_eJQhBeb&o#9WNZ+@5>|Lr=GKIatns z$-9OV+a)$pRNt>I=jiR8WTji19dCJ~090!ZP`b6Y&uWG0&y$9Cy*o!GIXzmcQW%~$ zf1z@=H=MLPN``?OwU{heP!96wUyu0dT&-hZ-^oNU*Je5=yEzcOz!{Z|{#|<{^+}gW z(ifCWHXc!g-e{aKIGH)_G?aJtr0s=gi$WgN&n4&{XSU4?|5F#ld;dh~M9@8%+NmP6 zivy~TQ_gDrl6#w{dsxKIIL}bXI9dW^V3Q^iwmm6~mHp4RHa>qs9<+ipx4& z$fkuwpj0w;HX~ZIi=pN{;}64Pzl@(a*cq zxttdF#3L0Zzn8;G2)3v(j)7#>Vt3o@rEPQ=ORLl!5_g=9=Mak(Kg5bR8}x3bMPso$ zB*a12VUHxSmte)&?wiK=xtQTk4oBB_bDEP&$4~pJyPJNN6`2NOIh5Ch$K`x9Ia9_S-1buh;xhq-Mg?j)Hu`a+pImnPgBWabxWd$C@xo@v1b|W|R%$cE+m;XnD7{`RaSWtb z1|HLUM)TDbIBahL)SQ2rIKI{8pF1}6tB72Z*r74_sCcqX+0%y(o(OYheVzfH#pp|APG(2RgjQxSHq zP&mC!Gq@)?7pC<%`tt;SJqk z*jnhhT;Ty~_{R^MBFZUj^AavdmR}Dj@sP5w`!-wz=vuovKOwA?eR)bL04u8{h`-t! zqwb~uL0y54{Wt>^@%<5p@eGN7`ZWKT;#f!tDnif+-Q((Im0liG6E zj#t-OQNyi(9VJ*KmuW8Byv^vM#)s$|TvRvQ__1EX>TWPE;rY?BGpY6$UpH&tm2YMp zkn7Q8|EHCO_S!lTR8XSC)ycX>V~RtQXYM?iv4UZvN$-^7i=xYF%jb_Gw2 ze8WR-I9(jU*o}@lw)2LFv4u*#HWC~b+GQsr45AwrYr4ugF7t+#4V>j2D6M!k6CDC| zPcXK=k_Cp^6Tg1`n3&DpOefofX0FBct2{8r#xz>P&L@> zttG*3@7M;=sj0+ugZ$pVT(0ePh}IhMF%5X`dxgdD*{n^v^I)P0OHYgc?VN7#m>ZYN ztsgf7+BSK>aNxn0)jXHU3ORcjuqG;D3<4n-MnWVlM3Kdx57!^7#RzcT7r@}RT5g~v zhrdZq{A|{X3cY1hq)5H)t>E3_`Ve}5`B6BD5hLpTnBtc8CwzYVG|3d_(diPl@&WWb zP+Ci_JhM>4CmgQ!4h`O5?Z*)s)X;Bd%C~Q26!ubf7k^! z>U#?Z7X?qcMIfezJw05d7fyl1{GpD=-+wa_)?oEXZYnuIy_w0n_ZUyNI9)5f!R=UZg0&|pBmr^;YZw@s@l>Vzus`p2`cx)Q zX0ncouJ;Hd4wTE<`tQq_jKwuCP9@qJ*$$v|8g zq-$t7&~HM1o(Ae~t`M{xx2)JcZ7p!vvwaV~YQdx$s=L|J+vT1jRi-$v+`6!!BI>Z4Gt(MRUW*&__}R1=NSu1$M>%;kE6DP= zVmrbJn@ILa_OZF94T7}z?jjF>A|PN}JtZABMG?KW?`9QKqNYg0;2$G0X}_ki4as@;enfxHjjf_-a3KdwdS?1x zMba3-sg`KkSgTCG~fDnkM9GlI1N5U?kUlb~pWXgF) zKKT9m-1ATSe*7Ja@Tcz(>sj&GFmdQdVNKU7h44%?8Z|L2rjyMzuX|f$Te0>{Agxzyer|TNVzromL4k}|_O2_ktw=;5>tAs{eJ_zx z@f}BhFx?g>;W+4(;3ZgI{PB!S#B)yP&J_Z%VEP*9@OX5B7qJ>Hv@# zL&5>q-hU(v`ZIh*B7~H*+~{26r;fl@3wPnZj*uAE+3=0wLGk9sH<>GJi3N?Kt)g3x z$S?E%elM^yeAJmCr^aCk<@okpbKG3lq-*EhL4XWh?Y+pLmtU~1Zsk$#R?q?N2VGgT zjz!1TUL0sIg`#=l7T_^r+pdB~}w`gvp&GsP+EEb`6;pm}?oTqpy z1W%b!m7*P?$|kyBO$b0AyRcPZcEDPCO-PQfLs_T!g&;qaH^kyN*{EY_Z94FPa^}s> zA4J6YTu`RcZ(P;5-!DH*l}^Nyg@L;@b+Bv>#QCLGSwNn<&KBsX3G$ct=q5t(5{~;{ z`wK5xlxemRxAko>n@dlcj#YAe)as9@d~Fn#s=uUgPk!gQLI{-pM9-TozKi|Y7!viR zf%FEQ%j(6q9GipHT7U`>XVI=JaB9+>8LgCnYd=GuGLxNvH*D(2Y=h8z14oaDxI0A2{OI-8G2*TUb zN8ic@o8qEj71()vdX)1>(^CS$Gw2TPv(w(^#zXi3;sio)pH-?pZvs8~BM1F#B#ny% zA(iI~n*QY@x}~DU(q|2CR^5vAEeG3-eaI>DIjb$|&WFv0syx}!FSR#*4jQ~NNOqUK z=4>&-EapA6wy{P0svH`&Odh?6+A`f3I-_?NxhA?coqgW?fJUH%0r?P>0kSTRj*dzU zQ?|G8*v>(Zv6Y81B(LIo!4GIUlxn4wjMK4CR}T)Z6m5nGi+X0^|r*?Q!1Q2fK)uu6N!S zBPll|cJ4blog$I_BFXc0k@emnKgH6_6w*xf(sJ+VH;4~l@Xj{_-aeiz0zQ2lsOvcj z?#9JYrJxf|+?=dj&=&5R05!UwkQ*fpX{iWgZ4i)=V?BRV`JnP%Jbt1WnENJmC8mFM zH~D~S0iaOCS$KkOma<_)bVlC@>N3!&ys4DG2CdH5!6snpAMuYtH|Na31dEKsA&_(m z`qj9-b3n#Bzc2B-yoriKVN#U8=d5tvf%p4-T1-d z-zH>fZ{Z-CgeIs6Hfr`vMe9d0gTP&e6_PB)2UfS8y<1zXGtqZ2YoVMc&{@NyIZZT1 zU!SUjN73258(8B8<-CPgUJKmMf9#MGIr{h_sNCd%PFC?+kue?E|9pp6$@6pDX1$XP zXo7`x?k6Z_;VHrmM-X78X=&R&|Jd@2+p@*1-7+60jiXX&4W+)(37*sB{{n@xeU@!6G_rrp^f#B0B`xV5-hZzn@ z1o7xkoMi^v!Fw=$(oVd(9~d21A1&f`J1pWb=JtryEOGIZzDM}GQQsrGK1i^;T54Fj zTrUcETH#QRgw5saUEI5@?2=T^jFU>S90J|AYS$UJMwcyC4u?}F%`;98xgClxpWu7o z`RfkaUVfCiix(<(U27{z;>%9q2QlXr+0npHEe%64F9pIiHa)vqNn#GT1s2A@~vV^GR_5req3p^rsBb*+&722B#09CJJT3L}Dmt zGIk3?YWB#-mdXKX?_^UFV-DBVS?cXy@N5rRzmtfZxylwwmx6|1nk0=XW=m@rE0;AI z+0o%49Ut`==cw~G)k#ZhR97f*qaR* zQq*emZXhwF`Zvpbrd`GhgmXZl=JXk6Bn2pTRfSzj^}gtQ_#_@P&RF^eaccLzNmXc) z=Vj4@brpxnVxj?PxIQ|%KOc%F65^?eaAl}fk=rWgO^+-+x zOzhlVyzfW;)td|z>ARn6eoWAdKJMrmsDAlwhGgmGG_|W)i_qa{r?EqQTlIWS><&j_ zp!_V`j6gDox#jUm94SUY+b69FGNQLlU?H`6Y2A_C>k6Y|^PyiRjqtIn)+ng-GEkzM zLAFA@P8*9#t-+%SlZ-!*y*#Eb5ooCD&kPD4!$IL8jTAk%>Ns2{(B^177}zRw z{f8dEBFk>@|Mujxk5ri?BvZvIG5yhGA{gU&RdQGi0}$?c+iLJItDY4^$IX0RPrq~h8z)F%oHkwu+r&$2tKHgo*l~~$yc#n z=oHem(RzVnBVq=;x`ViG8mAdPkyL8%N5mF~v&dSDl|K0c@H3r9tqvk$4d|$gQDl6* zbL__mre%(IQ&QR(eQpS#{lL5ZRXtV{t}}{GrWh< z>`Rx(w_dsKX@5`yMe60AX}$g+&ksy4x47hYVyh1y?bB%X!D8SoIRFe#cW*=+ctNSS zKS~5$#ye;}X>Q}C+$=^s9ONBZ4~_T79;q$&6Zcn14$^a#ISvbf$UWB_(C!dnI9w`n zuApSY7U#+li*P!ip4qDh3t{K<_!&j|UAAbp-=VV~pLA|gU4u8VgfW%t>=LG*BlHJn z0~kzV%_3=!)$cBBG{bWKQNW4L?u2-3- zVTN=B>n%+1b`M-vd`|b=KVp6pT<{vrwJaI#fesP82e-sr*+Oj;uBRUbWEel4WH!C* z2h#$;#KIEOWi9Ay3Y1-`)hk_R`0=G8@nlk)x`TM%R2oL`if33529Cq%_8oIP(97yP z;u?n;O)LVGNA0_n`$LP`HF8OLAO0X-xt+74Lo}(3%7O!8XP#q_-DIm=817mqNHH;WM)B$Be+qi_IqMkD ziBBa^V6#8G%vK&grK-2OypcMciqkZLZds^3s+Mc%S;5)0*Nu9?=B{6~*n^6|SATJ9 zaaegdUE`Z?y7{iY64oX)U8eS9JGK+`_)wj1Hx)-!5O48JzD-xLMXE*fjFFcx8i&4S zX^>{-8Bc&rXFT3F?zp`RLLAQu=T|*1gO?D0WW}XplGxs=&3Z%BDMU0|;fa;2;?v_9 z8h}T{8=x*sv7) zCF?WEvCNHCUx9`Pz^k>)+|=*@V%Xb=B@ZBO8LFK`bx4AEIRyNR=~;9G6EpDmc^$0* z5DglhUb2J(9)Ij@4m%j=Vor(Lw5%uSS%?&IbVg5D+9uA%DWb(4-NHbVwEmvexl_o3 zQDK=pUek-z@#+i%q6 zCs8ChgaIKvAh_ir7+fh2dwqepR%_T^sN~^(m`wRUZbIDj2Q|c4TsJl1XTaa!ekPbl@x{+>>8X6R&ySux)>-qVwbD#6P znfH8{+1K7{eb>4GO5v;#kQeK1N=M<{;8KxxP(<~z4TO?T*)hySlWd;AbrCkOxk;&= zm06A0->%aMg;r|GbkIpBCRr*HgJm+1Wuma2cg`jQooU_+=-0{){=}w_`r4m$8EX^RTkKC`&FuUP8$>ChYN! z`sq7PtR+FhFLsc^{t42f+a7GeU9GeLE+?}xovW1Vg- z-Mro41&uAcFG3RduF-W~=Cpfd)C7g&ibXoLYrPRQSK>28^g5}mQz+ReH?HaZ5rU#g zPo>F(IGA=ychvWmgZQUXv5YH+G8d zXd+GpN`4}NpOYtTU**D&mP&|ege_A)^JCL%Y$8=5u(cRGL<|E0V6j22VZif)4R7a` zd0T){qxZ1)!+CGU)K5|3u3Mf5jtxBe(r@#i?Z|*Vgw8ycs|d+&i8z4ECbpo+oc>F%xA#|HxA6c)d& zGZLp_2oh8>1|F9!hh_{`M8*e60x&tqH%$roW;K4N^8Cy4!!W{XiY~-btU`y&*k<;2#029>bGh+5Hw>rDT_d8r(k81WA=OLIeC%mDL|6jSMZ>`~=>peTtf5pWJ^ zdbO^1H_SN2_-_=0#?l>5cgt08mHg=eG zHI`XTY7o#($RMiTc(|=alXXTbLzJ_&wpRi%C|%$5cZ-b^!F{e z|5Butli~U}BhUCzA)`?b^I~W}UI)*e&wXD~KE0tD*~N7YZR6d*<&Dtd|M*TF`f;fn z59x*zP-FZ&G^tiTjRn)9Sia-YQtETGaxd2nZqs07{6j|~V9hdUenh&k6T4Zy^19+x1uoHV#byXDQ{>N&>f@i)Fmp1 zuyvf%XvJ*}S*Mk=xt5PBvDM@@Yo?cSG!QviQslCr%`b5(*Vdth>o`TPf}E`YI@3$Q zPwelLmZmPaFV=`$LFI)1Yj=4G<*|?klCZRHYTsNuxNrjKb9HLA8e~$4lzdQ#I!pYZ z$~Rd)!m=^l7c)@AS*HF&rQ`j$FYG?ypO2IUTEpOD*ZuXuD&mD~x!fdB#=OHybIVNf z*C&LDiMrHpma9;@9h2?ySmN*SFJ`bB(%9a4CZDtuc;W7bx=f`{2g_`&mV%foPNx|h z4hCmQ!wN}xJ@0t#<P%%NGAB!*ug1O! zW$cmdRNhyX@0smwPmn{VF3jGl(~GG}-!}yvGCZ(fY3`w)th7~Kf1qu(E%_pvU@z|d z+HXdPNuiva1q!vXgFD6t5oLvttwmT+oh;@AHN$(6436@x!Porkdn?<#w;D|DJE3LR zVi6&%YJNk^CEBR8ZTML=q$VJqlB>q&5lPkZI~IST)EFGp!`OKIk-X3I ztYi}Rj4?qV`a$TP1dqE^xQh*ERPp~eI{#-HT3`eZY}9O*A;d%F(3_hojsM=V_u8lh zXKQN>Y8+dwwg(A3O!Ws5up;`SBZkOO7T{6E_6JMB2;TJ}y{nNW+c0Iz8;5be`*qfU zjUcV`wM*jk`4M7sop2e8O>ru06kL?c)u~#d^1*UWX%SijLUim8TQXuhQPk$K29^ud zsr9BSkO2#@O#IG@su=&{k(W;<7Kj1hUF5{Wse;4bS=J&hCFg6ts+U_*BJ|<$Qxrw`64_NW zj{Fj>TA>{faM>Z6HnuMNiAJoW3b+dr395@;m-D9Un2`QX?~N+CZ~wvES`uhw{+^=*Fe=|GOh z#fx1m^J}GNejiZ%YeTXYwU?633I0AT6r;)H5w6nnyRT_{{~;M#fJi=f)Z@9`4!}mw zN}q?o{akw^C%lt%-tB@i%07QJFr>s8cF<~@%xqXNpl)p?dXb_-{b8SV=G{-?=h}-s zaNA#ztmbq0E#UKI^7sXRC*_xGuwVIMJMS`Hl~`75LlWSRHP_%llbuXX&+0oxMQ>Og z$+NYHdZ;;mU8cD=lDR0rI7MYl_I21ivdKgmb-nj)zIvC3=Cd^vn){NZo*4K-@T-Z# z!T)T*P>nD4BN!B59fM*T)j||sV*)V4Lk)m)TZ15Srok~;7*;nVZ~RB6Ek^q%i$*WX z&$-VwBwg;>ff<*jOzS5A%sBP)f6q8=?=>O5z1OeJ>av3`z{$hfk|nh+u4#~;!|+UJ zxZqh=?Lme(-#4pjtZ{vqRa&LZyCN3e`t&I1{jh=h9Lqt{9f>(#-b}Ce&oqQc3dPyo zK0~wjB~*7fK?DG3+ojBOPj>>D4)s5Q=N{bTHG6AVuDj#93-grlAEJm^Qx>$aj{SE( zs1vz_PEd!7l`YHdUA`x0bCX`oM;8=RaztSqe-EQVt3;4Wrbf`Mjai5QzM+joA3mWr zSV$)DbY0&tt4yE~6S;b<_x%KrXog9m=SFvy!t#l9CZQZtb;gVeNCBiW zG%08PXJ?36a#dWRSI2y}lT$dN2wzJH5ac>%?B=8fHSE{I07W#1i}9`S&E|F80DCX#oLL%?y@`93vl9+X&eHPbInsa%QWBl zIZQqnY*I9F%58ssr38DpGXFw}9)r-84JXfkfv9U9Ts3AexTb(=m&2giAJ|Fw(Pjrl zt;JkYs;?Rp4gTjAejuZS&XN&5XxeA_YhjzT;Lc7acg#dweVsRx}a6Q(QERk-05 zWi7G>0WN3Aq0`82gRE0TWEo;Y>Q2YwTwPv6U1s#fnPNczg~~d%gg8~HGHCS3D(~oE zlQxqGUgh`~`KG5*($Ibr8yT9&8$y;jF3h3uKhzg26!rmM;c5zhwhJ!0Y$WjX%n%35 zfa?}t)D zoba)`4K{Awah1e9Sn9c!$>D@(>Zc#4Up58SN0K#u+g7P0M(tb{(RFn#kvBF~f^QcY zru1_z2vl5>Fe1>?hIQOGx74makv$``H&;nyq-J%`9s+%VSew+jHrkz>%PT$dd59CQN%@4EPx5a9*Va0C{wK)-2gH_i>>aKwuZ zc?w2Ar)|$W;5;}d(_UBX!5jFhgn&|_?UYH3`BwCb@x}$;KoH|dq|U{ZtOIVTX%MHS zrFUgeF9&$aVNT^4sTRo@4O9zT_rsD;V9tA>A8P6}K-wm4W+5LqtxdaB2PGE3>diw4 z;5~~P)B3jbz9dFu8VXtMU~k-OLH8>dpQ5AD{unZ^@A&LdZ00hfmp!>!U7;}(Q)-d{ z-QRGx50ZJ{N+gQ4B0Z(8-IYRZ=K2b?=%36&WS+Mk%C*@iTblx`^(aswo)+1H(tf;s z3gk5=MJE|DO#FSa`p!HzW}WEY$E9gQWXN(pav<=0{&`N#Ml~|4zu8^4@8ZZ4Loz?y zzP*4G!rt{a=Q)+9=}%%O6)Hj17bm>KH1z!BUke)DhR1mVV8!WMr{C)1+G1Og*kvWJ zUw_>WknyEy186+Qhfk@F3=Qgn+KQFjJ%LK$9Bd#`QUbC3`KPyDP~mGmeq>))OuxOX z^OFARIRy4yPxSmM?#L1V3`;ZHKTQKB6v4w^{sTf11OGe&)cOeM6aR~UrBp^;$gy=%F9 z0X0wL!q$4t^|8j6*xnDgpPR#&1?@5{Lo>zMrnI6l?o$iW}F*Szj04~fwIq4{#fvD zebKasD}Dc_OS3LV6KWuv$x#_$yd9=VnaIRuhrt(3&sPMXQu3lcnM?rsqoiYsJrK(4 zx}wrr2WF7~=v)zE$?oGH$3+ghHVgh4Dw+6yHH7@a_^-HlWfsg#Ytt+dDzrjSi~zOc;UhXq$_CrTcxj8#q=|+&2fpoag5}LNV|c_zr+@_g&v;TL6gP3dVPeJ^waa50Zu9b#diIz`nxOgqrVP zhb6iooyu~h41$X?Esbcncd{y!)5^2|?Dw7Fy?wdIJx{d^L(_ZAM|qVRbyE-Y&A9P?iW|QmDEujWS<79lP#vg z5LbbdUFq;Q*s`Y1-Y`Un-V-bN6xe;!WFbkzbn*5S` zA_lMbmC{3#7G{N3>QJNYzCfUNOlp5TIWAL1_Y2&>Fa2$St%zBhnew8);G~%a0opWT zu_BL2OtwHy8YdxMsfU3)(krmS&bgaJPAyD6gCz|Kr;bLI zdGmb1j5EhB6W ztQOU97d>eosmaa7B!5>5RIs0JVL`+RbiUjCYNHvyGL+5+0 zwK{`xm4W_o=bzt@WBwA8-jj`3hiB@Tf~R}CZ;$=-x#6z)2=s;yU~-vavb@f}Jq@3e zE8Z*nmSsmVODECk&VQ$3F5B(%vo<7OqldnD{$A%Dh>D|Sxmd}r-|Q+mxDXyyAn9$? ztG_7;d>`2Qoz8x=%hflQ?`sdX1KFAR<w01Wgt}W{E%1Sl{E;X#U#;(5tYm^}5nqgm<_mlc#^rpw;)93fmS62FOzjNg33FbdI@ z6!3n2;57T>kRAl)`J_^Lu_ycdokU2)&E|O^eyUhK<^h#xUCr483jh-D4SrQ~U(EyE zH5xCdOjs1^{-H@<97f(zj90y9Qc>~29nX`tC{=Dl8nx{k0|O8&Tl=d?B@u^7sNK50 za$FWhll?Ip(9Dt=4p}_tUDLXH>#wVO{`8Z976#sUnHlsK7ssS9nW=kzc6X8Djl{ek zBx9tf3ho1-MAeBNuJZtzZ}hPJ>>r{32BUIMoKycE`+g_X&oSyBEqd~8{lfLcf#>Bv zYI=V8U>Ic^?cLp{2d~SH$U!{lS5*0XIe|D-?_DF&A!Be~vmY*kY{&@Sd(7SYIqLT* z_ph@E;1KxCA76VNh81Qx^k@ar=;YFhA}6*zG+0q8jEK2$tul*R|w z>x|(ikLu~kbEitj^}t~4-mZxsKe@8$YVHl&&9zWt!Pe?kB1(}HSd`Rv!-W6_aOoNZ z?+Q39SOh!dShPQ=Vb$q0%K_1hAi(72YCLM)fl_M?wunrEk75*{r^6Z4bLF%p6%64q zHkd$v$hU9%IVSSu-Z|xaPUnrXG`l^bjk>Q4RlAeUUzvGb+`;lQW7HTmN;PVDyWG|j zv36NLJv{ zBj|#Pyf`bYVstwY6}w6YDhOr~dm<7dm7R>OX! z`7>2fOH!c!mx;83bse3{m3)RrnVI^d1F@7HPUoJf2`x2s$>s`$p_ikQOJ-u!H>J1H znnQ6v+B0}aW4wdzS``-~pRnBE@-3&55W8kkFHPv18DlAV7tdg^a?DS=LE>ci!H5^=7mZilP#xRizb|;E(M#T;Ntp48X(GXOlWGhnNC_q*hCc+ z!zJ|M3mN76G08AHysu>`|AYi%GOOgs^@gQ)LNG1q=rR0Y!twhHzgm zmr1}~YU(KRHy=)uHtA8QW4Hl`dS7G7SUH!S8X7+w`a3N76r&E2co|z){|bY)V3oqV ztQI`5|#?m&|QHSO~k52 zR9YcMriQSG$TgnANAZA&r>2_2Mg6h7KejjwU=JkynFg^TyKEHNm3lV=-WyNVAzw7w z;D+a*f0S5W(=UE0aBgiqjjYNTNd=YlmazrUHin=@9au<(6Y*LT4QIBD(MEK!M7go< zg!J2~QBw_!QrzYEOA9-gl2PI?63E2ea*)46mYOYFl^~2cJfy{$!Ps;IgwLE}6f-kT z)X3~6mqq5018b7bRr(Fgi@~IGpU`XMtm}fqTOvPn?Co#I(W_PC%-y!%$e;9b-^*X6 zQ|1!c3ySKA!EQZ5^%^h#&-O=Q>{`nBAVCr4v`NEWvq_Ydss#gUqMAy}JJ&#($fz6n z7)~lk?mXF}p1|Wofoazu=(R zebuH%)^|gHa{^}REji50ok!Dzprf1T)7Jb*lM$t~J7vr0bVN{=3gFexdvzA0NLeC) z$+AWqj0L<5m?$|O0e(9Io2)txSL0hx@B6=tzw@l1bUBy9Dhwj9S6hGoaP(XoW99R^ zD3@vlAHsepwwGHz{|2abfug0q{`lj)|2cHD+;Yp|*vCVn|L-D;!c>OmE(3*?$3v)P z6H?F#dm=XmCv5-Qh(bk@5o&SCjs0^9;I++eE+ekb4`CU?9SA1F{B{y99Kc(asKDDdMnjmDrwYL(YzIRPUpj^jaSH?d$;ggxG@#rs`(^~qLTJXhX!vA&;6tJ~|$+Y(y4$%dM0yHz4F z_!sy#>U-_a14t6VfFvQm$F54cm74lQB;*}QEuY$Da=APFX*hk3dKB^Y>sOyCfb19M zpp@$W!zj3ae!f{WRq0}=&?rG&16{xmP~IBlMQ(%*mk(lYSO@7NDeBJ%GG>|0s1#TF zH346_-6i}X6EC>VKOv_mqW>s3Fk}LaV@Wa)}&JVih+zM<|nbgR>R?= z^L^_NO9YDS)cJeaZzw#Ea3!fbVZp;ZGc>GHTUOhz20RpxEh4JcOaY?!==xWdM~a(ZxS#p1#^@H91Qvl>QFx z(qc8a_$U$#O^$?<6x@eDNi!ZJyt8%9@_^4{Nz14UiIlD|s83NTtYa)Ul?o50H&142 zYZO*nz2M;`e~4;@(zDfCALQ-`taQ>1hvBup zLdS$eW|scSKfF7ScgDC}?p~>t+BOysi~bVX_W5{YxNo{< zp+bhNO#Wo9I(@<8r=cF^YON#lzPyGOwi6JoD!4h;i4d<>M+hc>q6|c3!#0&!f?uBV z(Epf)G4mhy+mm#xMiL9!Yjx;k$#_-9`=&^bx0d%x{2?N~a3a5d@_x>4C8NY#JCt?_ zko{W_Bx=n^i&#yl&s_evSRbXVD`YyL?Mz_@RWLM{iVHaRL!ZNg zFQ#OJ!*YJo@ZtHUTFJyjUp2%5I_>SEc7r*r+lf&+a7UgMDV-f_6^@7?$0KNlSp>QPzMO94)$iLz}&#UF^i2T)Vwg&=o2m(8S?w~)zFNgI&?bcN+ ztE~z@0cIScYCuOx#)<<0g`?jOu1jtiR;0p*=FHib{q72fONHh<2h6!eq9V3 zRkSF4Xd`5=H4lQ7#skE6#-@Hp)~&GRtm+;Z!xqw`|AWYSSwsk)b^1mDa6(MW^5O3# zq-psAjdl@(CaB)i1W_vJDB}XHm7v+BA6}1d^(vi#ll(vRS{_Yun(u;f#kLAQYZl8+ zFC>tO`Ytq^RWKCo)j32M4qRdjBs1%ZSWVWgZT-dXD#e|hZQ?g24G_QWAl{+C$|nMgZ^`MAYxVE{X_tG4-y@@k zh~-O@djzSuNa4n$c>O}Jli9qe_RD#@Ps~n-tFDY2t-Lu&lWJ@~}#{pF)iGPLJQ%f0p&9X8-1q`$IDNZy6i2~si+r8$JHeE4~RF9}`{18#zZ|kBx|@486()8bqjL@Oj0_D=&K?`o$t7fq@Jt z@!+)jgPz-3^AQo^#d(drZ74Wlpc^G`(t`Ocr35SN;*&m{eW7T(c&`mmbCEBXyc0&& zzL_Gn|9E@qbysW*3an#KZ7iUXpcwz%Mbqc7Adp3Z_nlPmYp!Ip*a?}$z}Cr28^22A zX=Z#%Lk;Qu=1%rhS@v^&kdWYlaw%#1E*{?Vzi-Kzppy(i53p2JYG+vqjYR0xi;EhB zhgrHb5t_ZJEe3x)W}~}aKG5w(d$u5q87OSnRTj%HZW+f3{`25gs$x9jf5_PQD0|BM zJsq+)Fio6EE)mHgr5okd>~8%@d0s-9K~AFsP|z4K)V=;M=m`P;zttq>GHa(8#f%s} zMelf>O|5}+W-0@EnE#5eApXabua~K zGhyK~)()_HZ9jg`UU;k<4j7tS{gZ0hB^9;n!DMcx zdlWIHnLY-e=$}8PPV??3OU28pT5BwZFS*VfG!GjssqN^eiw+nSI`tzX9z%P^YUNtS zEi7(7Fc27_??M-U7`u3%Z-nS;kco@c&+E1~HQTiE0Firwfh-Wv;+7kMCADCTF%hIu z!9PBt@57T?XRs_H_DSY4eo`Aq+~5ZMEg-N3Z>{J|k7n_TWq(G7vB5-hH@!#(;wLzo zBF?l4q9sFpKiA-JRxtk7i9{3nD>YpNjIz{Pl*!3n0jKWkSMs_q-PUM|K*>V}btRHO z#T?&ffrI%9!3r%%Ebe>)CNICA9uX`QsZguM>H*>S$g!?xYt~q}gG|VUSwY83%`k47 zkPRy~?fW}{cK=i6QtgV5Gzt_!>W2{32b5GVgWu1dK$NE0^B+-~-im2#F)HUcY}3b^ zeFgue)&jcM4F|)gwqkBU@(J6IF|N;#=!Mt}vu7W-Jcu;}gs-lhujjCy(UlN$@1QzBNZ?gUv_mG6wl^WiPs1xI?Gh#ge z_h_`=D&T)$K(sJ;(CcnXK&dAVw;`ZGw=gzI*(faKoovUcwm~C)tZZ{~ce#Zfi*@5J z7W?jCWqF;@qkt3Q9f{Gj*||F9eDfjMhL}KXD<96PSSyr=DS2Nu@ULFYi`bbvE^VPX zGT*1^i_s5cVP1JGwl?LB!(uY>>DYH{tmW7XqsHDR!8i>jJ_N#WT5GLI7a-#@Pa+h$ zo936o#JzpWk@&D-aaVmIT>8BFk+D?quUIV=puQ2Bw1?xdR1InT|u$bM}VpK?-()seb9>Djd1);Q9YG<;J zDIm6x+X+qS^YMH|v``v=y$F6o$)p3o9GL`c0zh`ioIjbX&jvbNDw}Q&W|AiI6>^9V zJw!5K0^Z?dRLOlUQ_Fd;{_*u&Qs%Gm@Zbtw(9-_0Kg{yoCYP`di%+Z2!a6H8oG8>Z zHiK>{o_d+e2vY?6AI8+aByxT0gPEoRT?BC8StybM9(!zsqiy<}l_s!_HK0i}!7BD8 zm5fMq=r6`2MbUj}G!UGVCie3zzQNh2SflA$$M ze|>}AL+42Rr#*5Klj;KIBm_D2i&zgz;R)M4?SIN1Pg+d(kuI+58NJ!9w=n1p1RTYx z`i_8(#RN{>H8C3Lm?JZ)p(?LB_TZYs*?I23$mvGm_wiAE>1@iDS9>{n=TZsG@%XF} z%i(8lS6z0Qlqwb=-8~b9^5TO@aB(SH0$lc5pFYJ=?aXgFECq%{y5!RKnF7i3f^f`^ zcan>CIX`g)y*UQrKEzKR#Ol$V4X8uE++XejFSi5KNN2K}-=*pm5=y1PuwjgSDv4!N z6A5SLBWHPfO}5rt0&jyzJ+iB4Rj94q_r}r)rqE?M06A2K#t;{b4)N?zh3J`i|G_y4 zBA)9Ir+gYtt^Fz$4QXS(FoOwoj_NZqy`ASjdX9=pif_Bcoh9-6ZETy6tenDMRZBY> zh2gb5z$w&^=SOxGIA>!@HnP$DOH3?0AtL#EUxTxtauU9k$?k~YR3!+vktO#te5rmJ z-)h5#bbBR*u-tcpR!cNPTh-wH(o_mL#Sx&Vuskym^~v!C$n%oX9&{SCdiI|h`};pS zg#D+_a#!fi>-vBbn@&fi#X>T8$^G2GI`))BeqZBG1RMLHxQ5eiMu$@MnvA3XBXcS8P7o4(lMctG7C zlfq@Ne}w$B-WHQhr{;`A{xX^+yek_ABLg&RU_{bFsx zc4ha02C(phEGmhCQMsw}rzVrRx%tD{D!SPi*m@Q~@bEZZ7(4|j2e{cJI~7B7warI?mkO4uS0CYE~wYI9r2exWB;7fA?XKjcp75uOpesW3SpA z1$6pVEY^k5IZ{`b4fL(QwR(7;ZcRrq07O55&9ViH4G!a_*xxwWOncbd!*Av1fGXCRwd zG1k-@uv~rKT+w0sqqb&mw~t2dO2w#E}fIYg}$h|9iAkT66ZUQd&ntr$y$C#`^#IoTeqrNO{$b^V@zNIQ%09cK5u3 zvpVj33oa4p$k}xAnfHRLo+Vt8k=!SE1u!YPrICFlbb;<#V9Vujf354$O$O*|sa^rs ztBl1BYqt}cF&012Kf>pG^`5!a<#7k*f?N&*j>7+$^ZM9K_d|v>&)t0_UAkyAIvlo0 zF%;4_e0Dx;hKy{LB3V%~w{Z1Bvs_~!4PLX53T8{EU9~;@_(`I&h?`EL-RJf@0atB> zAL>yr$|>QNnz#>RkZCdUn`*>(E()Nhi)=b=Uic`;uuY1qvk;IPoSUGaZucl29ns!x z?z7`^OfdTX$VKFopNCoRivk?Gn~wuXl|*;E;^D3C&*%r-mK>v8JRev!t1;YA?HS@d z))pb^lmn^D=kx`SXhbjKaL0;0u8XPkYhMr zWgN1G-L-|741+a%BH(4Zxo|{j&BR-xd)r{YDt?Juv0?TV1yLoR?H@0-zj3{P)Pi+X7gob4<9K`xEetju#;LQqc$Jpj6s?97@Ck zFP36O_oF%LzCTCA{O+ocXk57z)F2XppX}l2qawGIMT4pA{KF|ibm667Iay+!AKdE2 zN=duWN5k(aL>1oNW6k2s6h@b#xx_Xbj8_z`ft}ZI@D`&&$TPvi=Tga+ zaj&ci%+4yu!Ej7w{t*t-$VArquZ$qTgA^i_rCcUiyvcv#AIG12n566pM{aI}$ z18M>;d%f%hh}G{rQRiVWyYT8?9Fm4?VE-p`drA0NEWpn}q(}Yg{MziQ>;8(=Tm2@- z3+yXyUD6tQ9F!6Y89X6{3hCWtb&gP!t`%KTtBqvl{nD##UXv)oL1Ja6;LgmPRV0~U)CAqL-^3d;bLPgt2bnU*-QisFSx zc67V0gXL>~{0Fns&QWVS^_%%tD^7C7`LRNqsd8rca}Y+Si|ME=x5M&;%+H$mRO_;% zyc=xj9MLzcx-p~;poXDT_H?sVCvjC8-U|NSZ_C=GjpoB}3dL{fCi>`KbmE!x+dEgD zr6})Gz!V{dAxLJH2$avdc0g~+vLsojm&e{%G~{%yn_T3T-+jn&Ad~-WnK^4Wlka-W zcdhZuy_js~1ALa09~uzpsDWn75GD8<&g_nPC06`qK{(aQZ96v<(;Y*D2=@LmHu2$- zR==4emp<6Z*e4Vd2M?1vJ`h9WrxIfH*DL>=&;-~T=XP`gi{ z_)!H5BOw9x8;%}9C7QXl#eudHEE6Q%+M*#E7Pyd^7^UEoHiYCe>mzaQ4O&^xloGP&RzcyccFs+NkS&p6DJezEo`bGm{?PqU&3H6xY#D7OOwk>!|c(#Ax!`HEw$7 z&wq^AezqAhJbMTJd(H9>1hp5flkCrhi&+@V7otoYajb=*UTknI!Cj5 zd(}jxc9q*a#4U(Eta5K6qYgy^?bWe1O6y5ejZx8xtmgUnLxDK)YQuDqkZnPBVI zTJHSbsIb?vm)o-r?8vcg>KGr+HT2V*8H+^!jvZY5s{>0H6>;;0#ne~QQ@6s}u-*h1 zicIpD8#~gtbb5UUPV!vE-HW%6?PMP!X`TZH{Ee&NDC#pc`k2(nSZ7T39oB`9j{>Sz zKaYMciEBsK(7N`2F$=o#Hw)&)x5FFMk(L#@9-db%90reeXjw5;3VwIqO7{&MCDG(O9Z%njJOg)i?|2h_MC{ixrul6@4RTl@PMr&>S^lV0u zasTMmKfvSjeQDJ`Jt!L(bQz_(PQq}`^JC`|T3tNq*7!#1Umh~go?(dX<2;dGD{-qB zhT9@w71~je3WjU&d$P(zArhF-lk0NeCP4S`y;q-TizN(@*`2ix@@^Px^T>Ygs-2!u z%C^^+&cGp%nKWR(%26dY@T?5dGZ4DFEtdiQREYAc(WyJx#6JGXA@dTXBDSuQp~*n- zS`vm}ZDxHKQT({!UizVJgbf7;hePvV!hbx}E68rfi>V+?BtNu@Gq^(hFf6^#PTc_s zvY0^rukYI5kNldink3Cmm&QYmrms)6`X?=JH?GBIFKxos;b%RB46@_7l0#wF!cS*;Uq$3w-+~uTysuAUU&~Y%eXSNF zu?-1xN^XzB%7U)1@R%@40%{<~SsXq#6K;lH+uPikPpQ(IBhiI2cry}W~x>#Z%%GTTE4|;*gka}#iI|I6v2+bPo6fHWzAE@ zsaH#n3JH;`AA7OqowtN51>LAvgp{bb_-8K8!tY#@Pb;A}KfqJCY1cc<96{0PmnNLI zf`^%6Ivw@n@djd)j#lPG427mIAQ-EwkQDeBy&s}Bwv<+$*^j&+}{ z2T8uI2BQIG>Iq?__BQapDYZw0W$YL)ceB%@R@?V=*Xn8t=~W zS(xzY`-CM$C@9-*ay56KS>I?`72BZJu1>=42N_c`;}CBR{5)RA%6ZW2ChvZk)^q*w z3G9AD?N7KJAu2Y#oSt*G>aP* z#bz+KLGU z*Y-zen~A6L3A2c&I;(5}M;j~r=^eOiuk#GY!)B6E(3qXic7R`19py@I&@tt|f1+P+ zVc%W1hlu14?rH$zpuQ>7;)(vUW1b1sftKR!3Hmd#z-}cc>2-YhlU=s9+J2lbTfuSS z$UJ$kYE4Bf!#5)-9XN_x!u1IPPZIxd40 zRVjm=l%7c8K1KZLQ+DX1-84K|YBD zqBq8D^a-bM(WAMX;#}#JKtNDnUP-aj}_O!53Zq? zm94Gi_ahnDpC8AENqz0`EBsHU*o7>;%@_!QUTHn6G{0xon@7KVG6s^jNRg=8$0# z%p8sT#4aD2Pr?)Q6E|q0tFU{5FViLuyT3aFCAbd$ZZj{(xANv%I)fZWWum&fXM+o< zQe^COdb&F`-wGa)6?rWdH@)q~Y=Y641!h+e789#?KXAX3_f(y|KCfXm?c7S;v3~B- z9*1e@QA{Jx_VvDDY}Md5L6peib&=X>zic1!*?sE*6zULtxuVt`yUSC|4*^RHyqEq;PyYkenQ96=s3n1Ul9*N9gH5kO>uHat*vZqjdJyZwCOWWoVvkK;0~7a zBFi__osc_krO>&*(W$cXwlfiV0|kTeuMZg?s44;1&7H24e!5ES%lLU!Bj;<^b|D_2 zJ?uR0hgL7&($Un%?^hh&?TFl#XZ_x5j@z@@1RZaOj5TJn!^Ez?SXL+o38NA&TPRqw zh=`}Z1l?Ey`-3J<;Y0D-V62M=2{Md((1;fX&engE)=WJ-eBB~6F~miE=7Hbk!(q(W zoYak;naonYf;!m}lYLO~=x7)G0PvI}(_zH7=tm)?OS4)IK@T1awO#Xkq!abH2<&WE z^_oM;$U5r445_fY+GkfXA4xM&P{_2tdgGaRx|);`&<7mNOzhDt%Q@m<72R)z4E>s7 zEPt}kvG~70dsX|K8rAv^Jo)e=Ssc|G!C;j*Wn`wK;)Xw+7iAZ?9rkuTSTWaVG){Hw zCddF&GfPqUS#QC^vuD2Us}m{@3K7qrkLWnzOKp#aB^uAKL-z|Nn~hGNnDJaH_gYT< zVs{vI7A12!Bi%#DD7~{hP9_A&zGCK=^7vSwa=q?m&&rlbFNAW=Y;(9iUi@m$ZF37H zxH+1qjH&mUpqaxewST;^i&`-xz1WYK)V`f6QN2((eG!7P+V$OS47GT;Ix!9n$=r^j zbgV?ozj@wxN2xWt9+8i6xp_>&DF%*tz);L$lTRXG-ea_YnKj&tQybO(jU;Y8e`Xw% zpLAZIP7t(sTQ=eop8&HQclcYW!$V-MTwUaBbXDq9TRMioyq%*fEm@CDW%hZ`Z4*=s)7U9RBpWONzs6Ku-+3giGOk z4+PJ)lam{KBBG?pR0y|^Kteyj-vfQ30g1T%Ot0_M;d?1&%**|3hcorYf(1hspW6ga z)k_@Fyi4D`WMGHqz3uTY)?-#+R}(j3TO*zDAi&&$o! zEnf1Q-bqiNiUhN4Mt5JjE=GmofEK)a-1N31cdwi<#ryJ9Rf(?M-*B%Y`72m9=$AR6 zpP8CudI;JcvkV&@MH02z{b9;K4g`AYC)cIwX-c%>g##0qv#;^>43TmT56`(yp?V7% zoLTflmM46tez7w|k$qdWow`C^|7@>6%lOR`>q5W4?!w;6v<{Rw2Foh3l`Xy*2@_m__Q=n80JeZMwG1eJZJ zQhWO3!$4_~|DK=CgWkR6zH_b2TQ(rnoSeZMPa?Ho-wM|Dk)9OYy*@d&6&dw^*g4p3 zzNz^N# z5(cz}82G4_Wj>+XI3lhWqr5Iu>`E@5$yzb_1>Mxpr*e|#I)$Gi`6pey*}nDyOKJuu zt$Br}19%S=SIuZPbI+$FUNt5Y%)hSnK*M`(KfkUr4`f2MlvRGD8TGKWV6^vx_}1ll z`R!d`^`M}6cDa@B*49^VLGrFwvRaflzLo@K6}7c^)C6^Uw<~6_4Wg{3Vn@9K=aClU z70_w-@>sL#`RJGj_ew*6;fA*8am42H|Izl=VO4Hh+qfVpQU)n4AT2E*B}kVbAdM1> zUP!|tWeWzK(jqM>-JmGlDGkyr7F~<{CIWk(_k8DE=RN!P{jSSD7F;0DGv=80xW^dx z9Mh$^Hi~R8pKgyQ51tdYQcejGhB$WXD;|>9h!U|o>;^lK6|VN?){VD~&sbA()j74J z-#HcVttV^lH%zy;^|Zzmnv8e!4OEU1)FI+Pw#TO(W*(B+Jg}S1EVkK;*LvKQ@-hWe zHmY5g_d2r}FDZg6a&q#wWDP=p;rxfL^`X9TM5 zLO-j4&#zzR$8Hzpc?l!5q$EN|SmNxv{aax>D+~wJWjpmo#UPh!2na=^mA+0zTQ;uo z!^Y3+!;_(*5}kbS3Aa@X70nUSufD&2ydQ4UraOV(Q~#XG+ji1VIX6Kf)RQ5tXgQA# z6ywKa{1zdfFw1tP*Ex+Cf8uB9zz4eC-DY{?R|5uY!ddY~B~rI&^pajbQrHJXP}^cP zKhFT>Vl}e;oFdY&#zOFF=t0#nJg-VBaqZ|6MKv!m&q?3bUKS%2|ALOmR}tQO_ic`5 zKhkjH-hTKZ{*+k%*$Ctb|JBgS7iGakMPH^-L$%lP>rVI@yvV|w@W?_IPhJquRCiDx zI1^C3z?NLzB*W`B+$5F?*6kGcZ3b7q^Lg^SifI?iT)TpV%EK+YlDb5O26TCzcB=;~ z`ZEf~K9};ScReb9;`J04*v|*z(gbCE&sXl6>~N{j+wrUxrj0L z?aj&SZh_secPuLo-zQw{EHY#nTwe)l0-l6pIS_4N6G9z5cgStBnBjyMSkFj#uT^!;ZyW{>fXSe*r zIvCk7$7;d6(ABpi?}xvk7v*a0E{M-S)1cLy;tV81t_vUG9$$1I+>83tenop3I1?U1 zpWrolEMW*sVFcwXHuKE`d7z^2FC7pP-5f&pmU6U_A*BU2}B3 z#!FCemUwsPbv}>ICFlLnKwnrRD7FGzKQ?)1RoD&li1MRr5yQNE^pU}lajv|m+QD%{ zMNmXQ(^lno#~*PZ%Lyj(C{hQbE}kcXSj(Rw%luXNN? z-tl870_?AQEz;?3!w;(qMkrR#Eo>zXyN4wy#S*1(48oViO)1usw*4}#R^l#`-Q5pO za}${OBsGkDJl{gdYOTCrOfv>kzUVC~sb)?fO)LrZSU9Coi-IaXfrabHj0^U^6?qmp z<|fgh{2d_gdq3Kp;QbM`RFTC`_|=QP96fjk=~GeoWuahBqZ{q5teOaOsL7zp=Br<( zA2Y#xFuRqXoXDB3x^~J%r?m+qbxzo5;kN*dWWRl$%on&NmJ=3#478Fax5PJ6_4BnZ z802wzBBQrM!ZEz{y>j!9oeWPWs7jiO;Q?eM^H*+GoDS9HB^^~=0nn*9Xe$Gp}g#4AEIJ}AvFtV?GNQmd zse49fw&S7Wy8=}d5}14MGWmb__)511i{^5dO<%W@y7{L6b;3?AhCe7$AZ=l}qdA`& zE9@js4q(|xM{_N0?j6C2UteK4Etw)l6+w%Rl`~r$!=rr@?j@QA6x#>GUl*4KuZ>{f zI9b+6j|xLE^Yi(?dD6eT&FQvM{w%L*-U^@aOEIX}QOQ%Qj(+IPubVB+73PEwW#GA0 zujQyop_S=8hUqo*Xy650i@# zrU7?*rKwl4d3@N|n>-~r9zMI+S?m*dTv2B3;zUM+VB4~d9nYF_f zH}9S%3}e7MYWFBv*!uw{V8VVxj@|YyGmVq&lZeRs0k3v8r*(r*_wi;P`K{!+AGM=wJ8a$`ArpGh(X%e~v(*@Pj z)R2umOa9u)rOKTXyWp3~x+5;wHpP21Usg0z+m`oeY79i3j>?hFWT(U;l9h@5c^QcQ znbfYAv-kBEbDFZmPL8rlhxK51Ek3@oUP%fifvLUkwq`pSUSGR=%60g3#9dbtKFBNZ zB;R~#+AUr5=A!)f9mu?jXgJ(cBPU{e%rDWl>tUa`wn#tgYy~kZL6+#yV!@AcsZ-1C z^2COH(no6v4acn0bw2&uyOU8$=MkU^L;(JDk5bu@Kqa@%mCwCM6XUpRpOU8isQ3}Q zQCe&VSq;s6{4(J>9tH=uY>>sV3!vwbJ3?+Dq>oMOmPU~re^2_dK)~uFSp%gZFsBfY z7U^RKMdHVZG~4k~2~|+dGQHQErgvYn&#ZZ`&j>U(N=LMA6L>}v3 z6p{ocwb%@G8!R;pZN@S+0}LLRa>MTu<82u9xY6AktU6UWeUY>THcD*GJM-pNGFp&# zT$8l;xfseP3vC>9)OUZv(?uqN+?FR5HTUCX3NCgR`#kPeBs|`MMR-!N1ckYM z`yd_$>fSKHFhYpRW7sylk2@<`@YF=jjWv8!+ER$z>saF8I*A45&KW_u61>~`;KjCa zkEr1iCkfxI)dM*RV={&!KQkERb)x3t!MUS;eL*T%s+L%nPA4UG!VY6FY+#j*D{5<4 z8*+EFr?M{~KW;A|KgrNnyA(RA>K8-;?c4?BtrtCWKTu3Vlr(cjNk!cXtV=9*@OSxq zOIV(1fx@8i_WB7*5zm!9)w&^Lcqsy9D+d)9-Er-pc(yaLkNMiZ?(Xn4QvR22ViiU8 zrCvdRSQuc2$=~kl6NPq_+LGE~C(O$PhMal|*b{7q5wl!kjV$K({&tgQqo=Z{! z&3^c9W1E+Jgv@cGXSqS(Vu%Wp4_Xj~C_t|@<&Q*3))pJIuJk&C?GT*KWX`g@7TvyT zk6wj1KKTQD5@Y^N(8p*GDb}0fzrjwhq&d(RzEREoQg6eFT2)yW!Bm(__-@Q={|{G6 zOXXm)cR6mZG!>h5wzJAo`!A6kRqX_+gF`gXPFAi~ED5(w!IG?W4@y&~R*lO|ZeI4N3-y&&j!AAFqGD$JvU@8F?(W_z zsD&IAX-NDRh4#woG~H_UY#~2E|$I>6)-*`$RL22(!MAcDL9IApsG4C>vZ*Wq=^< z5HQ1c7>Rq9?Y|lg=F2wtfr9fRbXrFt4Hw0$#>&oSY(x6?uWMX!Z;C*-KW8K>;~L{F zj{nHOog}Lv#^ZHk?4LMU9@mmzJvF!r8#a@Q|Ju5df{CUY_mOF)UB%(Ke{>N zK3uTjEa1LaFx#4-#$L7kq9W^;VqY2aKqeR{5@bU;$f%u>zx@_nw2c{P_#9>VW>b5nvbPZFLDOZF3&B0$1kbHt^ zh`eU;u}}ctE7>G+6nYBnhx?*gdPNqJ+1-hfIwebH{;zVq?d4EI$wJ^`xpfp|fqVp6 zC^Eup?}?bKFeX?u${X?aq>8zpGe3q=^yIf_`Ui6lWg1L2VAL67S|`N0CLf9o9}N)| zWom^ts%ALxE?C*Sw=}hxH0C%X@^NZbl_>YL#cIq(Gg;o;jmX^j2G-0|uJ(j>yma^E zA#4I>TA*8Ig6mejqiwq;ymR$csy5^KmbcMO$t_*ZAVv*!gWk8IilsI0zu($C7Mup>jR6a8KlqLPvLt6<35qlGd-76G!Ez&q0(c0;& zL|Q^;S^yS;;KRqbQWp3j@}ehC@klr*^dQ?H5Pjdh9UM}nE1Bwj)%I+bL?3_1;nvZ08t zzNiMxRvklK+c)0yd%SIOd<&OTeNdZ8$hUV;02B>Nq6@?^HrphmE$iMrbjHzD9MP(; zCF&v`hV7)9Qk3PvvxXaG1`&~%2Q|GxGVPhZXA%a$lNL(FK24Mnym3HQE4GQH@_8Vl zBzmp-gH7)hx^L+AuGO}sy1&(B8e!4XJZ!NvX{&2$zdsvioiDdhsoHYcWNE9B<(H*SV; z7*Njm9DfU=liq!!Q3P2N87>~iswDYZ)|*!mF!i2qBZbI@n!k z;+W}u_WqaHr8dWI!(Z&nX1k(?u1BC}&omwQ7&vg%GD6ErM-=*eh~Mr(Paaq9=pipL+Q zQpDu)=s0b9^>uyQK%+P6QDeznNar1=ic^_~qaVWZMNfAz;|6U%>8FIbX^I$mLYcH@ zk3Q1$8MZa4&NuQ3Mjd#=zXdHwth%!c)ZY?kH7nL63*21ZYRFJCCb#oCJPC z$D+3F#CDnU>J=o&>KM|ehzmTD1sC%fuPUazdz|Wl2vhx4-TX+H%=^wpj{z5Sz{wtI_rtCw z4w0wOmq^orOMd!8h#(8`6Y8RLVwH{L=rv5mpwSuA9y^NWmo~L@?mglbMyDOG-+FPc zH}Loc#l-DyvB#skdhPmsJXZT7EW(Jgw2a5u!FL3hxgi_`2z3=$8V;XXSAw4Y9m7uM zbFTH)aNwTAZ|*V`Pw2Ad8{CnY?&zOnH7QrjuZeM4rMcp>4{V)GPTAq6;f9kZFhVu9qFk% zx7S;bUsNM233^+}9&&Clh$FOrPU5O|SK`0x;( zOQ_hBC^xVqm)Xtk*==rGbG_Iwg#{Nk$>2&aLu}{@AUk)mgvEiFK}@%5CxrA>zp|wn zs4|&*!DKDDIz(##c&!%ik|1~T4^0xDr;5uS_b10c|NK?@xO$_v`X!vOcUXghkzk4A zg}XILjeMzldEjt^afO}98951K?5a5Ss}-Y{8@u()X8VQ!!#jQ2@sVAk6iA)Ehkj&( zbkK(y5~ro@@>^_fwOz~jln?Lf!D^2Tf=y{b0Hq0Bt8B=?yLqk&i96SJb5Riy%8Cu^|Qn zKRU2aTgaLg&PC1ZZrCNcVBM0V?wuQ#D;gkt6A&0HW^Coj8Yt#Q@ZjZU zs{6t4HKfaMbRi-MyyACk`?5}!5CggBN-_4jBQ9j!$iQ6*zw1lSorf|1de)0iGLVa9 z>l=RiWA)PTm4Mj+92395F)ZqjsG!DPk^WMI#@n0TP)`#}Qk&NN&>VU5jYE_06JPYz z6=6&9^90dH^2Q}7nE>-&r6(Ybqw;C~dGw6TXZzkq6j{X1yDP?S4=Y!0{#n_(2q{a- z^(^?~>-S9$gvx%>T|OZds(yt*KpDec_J#pIY5~INC;YOUT-r18Fng3tw@f+*jt)&R-IVlicM}&#*nMui3Frtu z_oII@!o`;xAejB8_mf-Rxqq4~8Lir`j^wk4xq9cZg|=)F1sVYsYOMdx?Ih>=M}J}O)V*EEU=6lEGdPC!_r#S|{7@jm0I> zG`vrC@4z<13H$8_(yS{ig| zu0L*^?UKyhGzrZzhVs9~dQz}I#IPkB z=cUh{BueU^jBv5B_OG2Ylz=tY`oT+c`KX+2kLv@q#mpeI<)#kfpaPr*xb z5y+k4eDX-N#@twbdL+-N_!S@9bIf?HW=e^=5asQtM?*lGG-LA{GerN_m~rX-=k9Q6 zm|rYYk^VL=B;2(NC^~;uS0DYR%TEt`KgS;q6o;7#VNnw({RWF-+tzl8sj>5bGh;vY z8!Yz!pMXWj;Slm6$E4eh=HJds zPcH?pTM=ENip(XdgykODgx_M1&?z)-VQpN4k$k#EO+ZTjA*FHyCNA*uSL(``qYAU0 z<_IU_!IOz*^sN!2 zmO_C$`vTbeL*eT$8~q`*0#{Aqjn=Ej`sV)GrCVC=e?#d$|zPgrQN$$1O-`=Lt#pgX_a zcD?rUoyHC}<3v+GZoJ=%Z{(QbHoZ$g%EsZ-Z1$sbP}Jif;Ess9uG2A0g;}$De3|_Pj?Zbv|x}yC^$m&z1V;?;PQv4r-HmE zk|+f1zEz91#W7Y1u_$(z*w)2<#0)Z}3kgCSs|J`UFU^Qi^-3%N6|4?g!1I^<`EX92 zhRDY?n__jEBh%NISuSI{1KTBVvT1tMY1z%UGrQVBZhDyc(g>oUhW5A$Si&0~9pF5| zeXLQLS8T7*KU3|>X2C`DKez9t;eANZSIR zn7sTG@HJ52bEG42F4J3f@}>6G#L!huBjJ>1lqhH~2-hnZh}-GF$jf&oj&>{iOv4q2 zS44fAQk%b>`QuqE3bHX6nkgcNlr5j<5ay#qn^FiC>2|apvYj+EoKd+Y5%`GoF01NlFYRu1M8NudNkrzC>;GnnXs1fb zLQbm|3czW{0DW2`flSuR{28nKuHiV#d~1v%U~7G8B@DY3>cPM4JcGU4=T}nCN=ZWnVpKZp=bs^@JDK$lC2-Mk9a({^G zaS@`Cm<8)fS7tZ((7HP9XtC#Jq0taZ#b@1@Ex;e_o&M7bp}9{yS`DT23Zf9A2e%c5 zsWrAOZae1**qa7E$JhFk=ZaCMq59)f5ql8Pg>R@Xze3uR)<`rC-qeyCoi3RxH`o~= zOcut9Cr5?kw~)>~oQaJePosndQwlMi#)|qT%|q7hXP&;`AjD!8qvpCN|CuNqbkWqw z6WUwP-!}9*aS>sN=;@JKV}PrKX}i0QMSmuHaH$PF|HLzF(lbZ#vA;mX^l!2Uh}b$w z-w@>HTnMXHakR{%&`_?MZvvh!TM1`7%Xr9lEvZ3fE3?@j2yy#y0!X|{`Tjy|_~*{K z&>lWT)%U(-kikc$R1%}gGLxL8#ctT9D0(_1+5J+zNgpMCjc*QdxYm-x{28@o|Q z&g92X_nm>E!PJ+*(K?fPpSO=+U>ksvr z2D_L2`n`qm3@FlXJedj>J&BOxpSa=Jw^ny5Vm^_R^)$ytqS*up|KCNT4hegXk(hUX z^lYB{;B&UFA+_h}wJ~#oe;ss$zUoByF8a0E2rDgaa$zac{z**EyL8~sky1BVdF;;v zEi}Lr+2Nvvf?Mn#bl92IyPweQo<-0q8q0r!Xx*q9B&wD!6-`tKSIFtt6uS|Z`v#aE z_qcURS;Oe=oY8^;M4VJg7^W-eShf6r(O6v_kV= z(V9@4zxG!fh&LS5CW#`*ta%m5@&Pw$&it5IF>55Js^>zHmOV|m!qd~NPt1gZ7tGy8x$sYr%R z0FG~Wf4S7VuxR_Z3(OV1$I(&OJ)Z5b%(E-xx&-q7=|}g`;-NIk5$E9Ik4F^_u(yqL z#>DaZUjaOeF@(klqa{W-d$u)Zz=iPfltf%s+1z(M?!D}{uoW`_RDI%tycU5#%R-T> z(L}x?H`6$t{DQ0(cbk%9xkwu}<@uT#b#g?E3I)pfvw_0DFdON`7K_@oVsS)!fh%c| z&8%7b*t8>_L956V*K8KH=0!~*B*F+TZ{}JscPUiMfS@iv`3(pmo)__gIVs%BYJ$zn zdK63zFa{FeLNM(-CSZb=_m(+2U2fM?8<|%*iDJf6KD}2`34M4Tg~*D_AZ~B&W6ykz zlV}3E6*|?=k|-7B4$1ZCdaTnOmh3MIng6AoI-mF$0y}*NcA^@J9!LlQx5Bn!&p4M< z8vKKyzTg;hx%u`(mX(D+eD1?I8`=36Xfd{-F0!>@SkNbI#T9 z@or)>5ik?P2<;88?|=1`_1Ux)`kALkzBEt->t+VCm?KIohgv{M%xoLO)2T+BMeWV+ zy|;R?_sHVkjWkR^y;iv^9eI=D3{j;{sCOBwQO1)mP) zAUPK+O}i4A%Eq;M7po&~S%j!2*>{D}%gYh%Y0d9%%!DziF>EDu1>91|lm-VE)C!E3 z+0I0IMgB^Nr)`1aHA+b$h>BweqseEO;1pxc1)4Y5KlTkBEnSNSH#IiD4bN!5Z=4<= zo7~J}<(I)<0-uyHJ-n6>-PVUtXlpbl*^GGE@JU$GB7_gRx}usRqd(*Cy+4)-2xjra z11p@%aQ2U&=Ce&F7A(57@T`#WpUigor8hCCmYh+_Dn%poP?fO*f_|pIlh8<;vQmZh%U2wco9#APPodx7t}&zNT!=e1;-Zr7fm>t?Zz# zVx<65VO92;?J)06aGJk)wguWsY>*csda^H3YBO#+$n-QbM5|6NvbA?JdEO4Fo-kSA z1_d66PBENY)}SIRJY2q^`NgfG-%-6f`4x|qOLTv}0sp6hIgYxV$g*^$a3G0N<%6EI z=?~FI>#_psAWLaAB58AfaEVIFYNy#~b0Nv=fCmw!V-q#Ov9rxo#4wR4EG-pGX{k7p zghSjOeMi9VXP@9^m*}X;Nb%CJ{tD$kw+Lq>U<83V^M$Z!@ zvFopv43F0Qnq4x|hl?g!1%}Dj-CaXS#RjicCJq@;&8tOYgFR2JeGayyh|qMAf6XQT zb;kA=Tk+07J70|H!LL1uRJ>>ca~(?}HKLUzo_fK%cZaKouSyZ*CB|hd?mIpve^czV zA3A6~o8UZA!hqlIn;3QFzNb2pj+^G2Vt_>kLa`Sne=T+my0zxOP@=(x3 zY*tft!qR#y@fsA~N$qNRQ%0=ITFYM=(HqoOYlLRlsZHS1cnT?Ti$h2{Y?)d``^<^D5U#JX22Tf>9SdC+=FO|L9PyaQY=cMvgDvxOJKV_vOHde%S? zD?TswagER^UZ!6E=+OVl$^ZF#%Akbs`(WarZ;E&`lUjOPoD_j-Q{Rj3L|P!Njxe0{ z`pEmhl_5&HA1dbv^HmaH<{x1{FYO;VBz%vEtpG+hkVulPo`1VwziO?W z7Y23ceBi!c5K+6X3JDbuF%&Z}-?5diI*JMEA~WDnLoCfo6)PsOA3ob$=z?hC61{oq zf0m)7E5@z334)@hzc27DndA$=m_~tc{>$+4KRDe#8|3$IK!Nb`w^gE2J_$eCrMmxM znA*6a(4^g4tHLf?Rv;z1=?48f*_o=i11q=H_$;Zeuu>=&B_FN`RKP891XAOcnJjDe^P_=Ou1gL^YyD|sG)%8 z{?YCRE5%py#n>@9D(7_40;bxy$so7TsfRciY__6%`m97wRb|tkYEULTy~6|yI~ugw z+A7h+lAqulLo$-7{RKz^9d)x(wnO+D+CLloDoT=U)xWzi%@`1i12 zkr2zgiV;?2a9We8SfU)CAI{V)Q#)S)DBt)R} zdcPRTt9iA1ErwCq#@t0y*u1A&wwoZ;UI(0MN!a1NBjDP~6LZ@6h;H`w&(V*5G>nR5 zY;%DGKP&jY-*|Ipf0LS&$LtOMFz#*U=EF6Pf;KRE0Yk@s_ve1c=i9r24#pe5f{kZ0 zIZbVO4Ni{2M7>0^^bvenPf{wipkH6T-n7k@_K50v8%pQjcDhIPDd<1 zFjuE6%+muFw^Qk`#5~ieTpayHO2ca_GJ;vXH8!FKw%1}kV9^XZk1JdhS^71x?XdzK ztT=Orh~@k=|zy_?g6P979Y`qdvubJ}N!=P67c zIIi`yW#kntbgKBs;JRC^MMWFvPe8O7&JyTn7u+^SI&to@!2B-(;osxPFXpN98jBg8 z)G3OuNo!o6FZ-t&@lxoXS)sU$<+Rz=&_O%0fIFOaIm4Ez>hnh{LmB=&7Po$Ke=JgR zBgen}^ANBp(<%0`6AbvV3XD~^a#jL%c4%;|=G3RyY@Y66RX5N6L=w@%ZKIYCoGD#)TR;pEEHXHlp#Tes=W~3g<<#@T1l29pJyl(P zX|gWAi%XExY30GvNG?nanNL0>TkG!Hu{jDKW195Xt5Hs%@ihnqFv80yq_ zv>O|>kN4ulQpu&09RE`w|2GixT@myk&g6%oly8VDcfwq^I(Ny;*fhVqKNQ@HM`_AK$kBV#2M&uNx-LB? zDDMGy$lLIiu8AHY7m`%J^s=4&*c^sXkqZYgAcpp_Z>HHVa7fmSj0MLYVx4eMw(R4=V}=R2OV1EAm0=ubVW^(@U#_l;2I%(d?S+Tq+h zXy!-d(*p2JDq^J~=IX}!hMoXfcRJ3|CUV^FKbK6@F&C+c@zbOQownrH`*B$7VviBR zB#hj=Z~lqv7ah%{M7lNu&ytmqk~T;W5X7)5#)(X+MU6?`3%+f@9xcyNbJuVKXbfA> z={c_5OA>~qlTP%Lo(&_(t30Um7WA?{(E|b}_Q17T%_xr3G04exY^Y3)nGmsSYk*tKiTqX69$-tQTn?Vbk@nYl7;u#hs(rnGP zu<0eP-3ufeP`26NiOCn%+@*T(4DZf^#iANh{0R;YhoxDyC`!gh=vTbaOfw5Mrn#^iI< z&=XpPf0qva2g}_BT}R5rJvpIo6xE)`m@RS8j`gfh&zoDq8)cAoCLXOb!e5-m-OM+- zjZl)$xQ+`$d5pFcAUb#ye2)&cmx#M_=&3xYhji^r^eDk`QR1JKj&bhgE?-#n4!*c= z{CMZ>ol?_#DwPNW+s*Q*Z@ScicP`ps@PwanY34P1S6iR5=n`xpq#5MAa_I^&prwD$oz`0{7W?iu5BdAoQA58zy%0|Q&!Wx$V(-b2 zTpWb^L(o<}ikST+Xnu6FM_N9D}j-{_yIG)_9HF znv5I_F8%V4$qyKg#uy#R1XYH=*?r(TYOQY48d2un3hDg7%xm#UL@V@i-|7_AIz0(2k({(1O`(90R)L zR*;mtR~=ZkJl`%h!_81i2*YsZjf!N^)OtJ*DKO0JbXiQ+C|s=B^H@Gmp6yJ~;mbMI z0B>3FPg10IJX)&- zIiVA%uE{zaN%QKTpNcamU%x(sd@9%d_KY=Q&GUY95Hzc|L5w(VwsBZWtfu+l5wm`P z_}xs11QP6$2|(2_azOov%d{(axX`3X^LCE^cW^Aa1%Hw;!SVv|1*>X#KPA^=-<$~f ztj^p95+62hNJo^ouivvGMAs$v=))mmjquk&VhB0L3M!mgtW$G`QMOe|)Lij+TmLyV{FhAdA;)+4zw3&aUIMr-gnOhGxNjeiTqb@%j+oU0VP>`fIf%rkmWg4*dvIycw z+OvCFKCff1qm2M6XS=3^9pjEzss`5E?oqpUD}J@j0V-bWeeEm>QcdH)zUNHDs=Xid zGEv=uXn00hc>GDaQi6@L4&8_+?!(p5G7jUoreJb9T(Y~b!>}c_?apvf8{1{4mc9ab zT}(W|*572u57{mZv+#AqYs$MnZ(MA!4Mus}&;zu@I|~ll+HY0=y;NH>5euZ9dPoI~J+C(ljikO0YJLeHKSH!J3 z&`{Av)vt!WH8#MOl=>tIv_Suh;P8L{NEZ;coRt?ETtD7O)_jcnDCo%Li-O)p#ZkX= zND&fchD9?kiiphvR(hT*MD(}m*P~)&@Ui*Q4uwY~=WZPbBi)h?4aTJk`%QSzLY%mawah}LvuyN1V3@U9be^!u$C43;VG)(zo>dZm$@~Mt`I} z%~DnUY%H6?*sZOap@b+9muX{oMs4>ay6vi4#6!=c@^-HUJyJfaKXMG}zG{!1^w&>= zAs+xJmSe@+uak29+&Yq00uxWR=IiLf85BbSt|PnnGS+IVLLZ)v71{MXCXVe(J{hfY zPEttVQ)EzzzrjP2mE7)6X~E7G%fGdh%hi7nL?udN(xyi_*Fiov!EJ+ijqHGCRvFCTG^4G zDF0?9fbpVU{hT7TMJ>I>+eactwk4dgtUZofkw=WA>p9ZTk!u7ihV5utC&|=`l1p`S zu6;?3$m&H~RBrF$Dudlr{qVZB+X_9`&)TMSzTt2L+-qObom}e6=-9D3gv1e=KD;XssL%PHh>aE~cEdq7 zC6t}MRBnIj&;Y7|{3B0!mXGE8q>4br4oGjSohENAp#Ygl)-6D0|7$vS_8SkGE|3RK zJy2QWW9HIL7Ax#hSKXZ!&KonIq!vhtm65-%8wJ&+DnKyst4BS-FTuNquil-1N}a-3 zOS-$VIoH}cCZL8e2X6lR5vZ%ZhgNmImF=$RqJ~1)NG`+(|7F2|Kt}9>EH2XMR@v0> z)K+D6_2?GvkMpci*iC}7_05aeg{R+;g|2(-NxKgiJy(Qe8ZoRF_pb#xUqH>V}m-jVE&UChC-WT448hMh;ZtYl!IL!x{F;;pj|J&$Cj)^`oJGZ zzOm{5CKzDfy;wP6hY_LF-A`t?2}xd3+C0z~is>U6yQl*7i@0{n@4DzF8oxmVsIU?y{hx5jLR0!r}=jS{%?8I4Vep59pc{! zA%}imwMUC)_0*J$xVNe{KmUCb7jC@W`=fB(AKH+|2MxMYc-l-@r4-rL+WIL-Z)M3$ zs?=(jxx@xKRn$C^RJRdhihAKWuRvF>mfi*aDEbDtQ?cRB--{|fXawgV+7y=7mfCPL zVTDdJ&x$mL-#JzoG2h(J5#8pH!rwec-nA>WROg8+K3FyHW^O01p2ctM-L(?hp(Cr7 z@-R&zrBTs%`~Y|NSA#!pm^N?ra9_ZMyNKBWS#TK|RBurgH8k1!!{w2%|8ku}t^kSa z*>GHvjRO)_k6H5F&}^-g*Z>ld=0qpURJpa)&6%hU8qEyxW+z^oXeVB{Ol`bC+UYA- zF2f!nr{gemoEBvdBTLOgyaeN=rnVJFk%_#LVy`1kSS;a%?XcK^b~tJ(7e^0hU5jz; z|0ams5W84%bHW?_i8P~%q*U80-5-sjE1i+sN9Akl&nrIbF!m^0zA15*(F^w44;M>K zYhye|>uL0AyU821kv{g=k{Gcnms;Ha)>>j0)-pTkHYx;%;tsKZmS4tVAjed>ic{6u z)(h!Aj%Y=LiuB-idsXq?g>3M@HJ}XjW%&T-`ttKYdV-4K#kmdUlrrgs5Z$#9bvNf|sxqrm zVskq+6Ve?OOPJtDX#ZH9+32H-w%-kPAV+5FIRMIXjevu{X_iDF?>-}8(iRvPqe^ZP z=^i_;J&y93pU8=LZP1@t1F!{EX!Dh%UsQ*9VXEjj$cV?>p|OX=ib9#^DnBvW-%zG4 z@&Ck;WOD1LY8(91`neJALC4MWxv5KRV7Ng1O-IbV=q~=eviHmS9tjGTd#S<+VWIsa zbrHp{P0n3c=II$!Ny34?T$^+GZ`LGSfXMrI1)A4#C>pdYhMUYluTK>uCosV@x?|$@ zaFq8GUx+!(w>S60dq#~ipLZComYWqIo2v6G>S460TlA%JB zXK{U^>E(p7|HsHLeV##Sj7r<=7l@y=-C%f?fMJ+&oHPlc%w7K3LspgHov zmhIa~ZBJ*C>@)4Ow6yxayf3;pzi|l=@T_NFUMa-zH2(khu$S;nw|9{*uPj9bC>+~W z6vuH*=<|RGDzz5kOK;E_?=<{vO|xw=?Y#-IamOjf-q?6cqjx*%bLXcIP14mOQuKbqxWCIg)x{<|d^{R`}> z3F>rQ3uE6QkLe?ex>K-7F}(5ts(A#R{d^;Bc8l0xlOxDgkoQ{>C;z+K=W+Bb{#8KV zM!gd=E`HJfrN;d&m+Uujd9FxO`a= za(^((oUN;&5j&>)V<(X&7ncw4&Ky1GQt8&|1`JssU&$E;Y5#A+D28>md;T!fZ+?Lq zN@ISmCA>t>|2?{dU|mFnpCI)IMNY>gi8AAjD%DStFF`iWxQw^Tkpz86F4!K;ol#*{ zPHjA%ogZFWvMh5(>BbfMcm5)C=*JD;t^faK@Y~p)jki!M!dCO$WhsQC?gX}Z)>DNbu9O1q1 z!ZQ@YQLg&`d>_rCBQ@WVV5-dhJH$`v`GEV(n)B51lynZ+#oiIO_+`kE&W8kVPoExg9Ta8g|3&_L~Xmt~gbU^=0N|jFRWQ z#KfnF^6@p`&pw+UR#BuBXgd(&FXmmJ-k~$QwBQyy_xf4_qmlIW>zNYb%Q!Aewe+zy zAcO}JIsV|9@?ws zn;$A-;Q2MGm5!cVCH$miJ8M5HbWV^E|B7R-Xg${9A_$I|yxZo_BIl%Hi*N_)%qO{p z#n3I4`V-YD4<8Asf*t-8e<=zu3X7IZK_UD3*#Mj60N34lDLe#FAl)j>AeANmoyQe5 zq0y%FeER>|^nXtAF}4KWHkf=4|39RCWmuGL*R_I(BCUjUh;(-&CDNS(2#EC1 zT_O^KbaxIhz#uWe45b26(%s$N4d3N+>wCOEzvq7c@q^(Q<~rxxYp=ET+V|Oa_Zlb> z+-vEA+-Jh5dpAqBr=Bm|8LJ7N84~s8tk6e7+q)yUCY)5eW6g`SiYqIb2aU0q-vXRs z*y-*p{>B(y4E^v!nx}N~5}eznx*~?x=Z>BBrL}E>F@opZX!oR?44SNI%Vze|lKK3G z-*%-lHV#mW$DyOd$ky`9yMY?r;vQm=(!*woWu&anZF=OqDf^5Y@^^iM`vJ>6qkFF{ z&tScOeg-N1<;%A=Sq4ppDJ#HaKI_%nXDGNI?meKocmI*Zz5n`0ThKS{rha>7AP#3N zx2@aiIQg?v68=j$36RV{DpO233M!-T9&EFsK~317+Nn%Eqw9TN@mAD!#)l6fxtA+j z{Px2d-d@KAHFo;YEAf_KK3qZjQ4jf80kwE9196Re94~-as|+ccA9Yw5*BufsoP911 z6O0=DluqB^Pi6P|FU8vKIETYG0cDCg$n*d3k5IjhL#a6o@-skSd&UWH=*kr1U##{R zOvs#Ujpe9`&2Ba!BGe4{`q$_9J})HF$q#)%VlnutqdO1L!u>xa@dMk9wL~pGJ~*(7 zQYVi^%@Ws;qTOzj2WQKJv3EL{rhTJfhIfIPBEHHMrfvE0jIkQU_>r2qx+Yowrv6irzAi_j zcMQe8_|`L(cr$gLX_3rh9;@4EmjGpt^?W>T5TaBje7aFZRBhL8gmgZ;FY12~8%yt; zt@wOM?V^&7!57JcM2v2iPSr*1ihIcUPhZASi25;McV=*t3JQ#e?>L#ut1f)>Y^!06 z0!CH(gTi$-+*jt(YV8@dx|ZYFRoI~F#a|}QSj)TnS;5oB49-7~mvsf2y_5y{S;~Fb z{WMB%8=Rwzny%Bfcb+nDt>&eUFb!VeP!>rgHJR%9J)Eu=NE1a9H}l3JgP`A!k`_p_ zt9;ib!CRv9A|(I2@_QWZhvPfz2SYBKzxIyLJGm>vDKaYG_ecv?n&;4TdEcxg3CMcamDS6I^ zkf@EFDfh0bWPL#~RIL(Fq`u#;jcn~qiK5+3w=M!&v4D)Ng1>5ubzQlIr zbn08tW~Y+^T`?Ia^sa-ws|Dw=5<@Nb$?WVtm&0Sv17UZK3&X4Pjkxoh&Lnzzt#bX$ z^F2k&NnkQZ>h>sU;OdOB)$;-o+q1u?@)L8T)%DQ3-s2+mob-F2>Pi?SVQ%jDkfR~^ z)i*-%THPZ)+|X*-$Ik!j-2c}wy>Q+ZQ5LVa=Lt3nkUwYRq-1uQaKP@-Gc%}V7dWvyAk!A^B`JA0PHu)8%Rl<}w@mJnri(uv zagf_~9=BOcrhX}9B6^8UU?QD4RH^5iD&!mhj&N);qUm517Hp`qU3rMGIo2=nqQfiw zLN1&*kc_~t%`~#c9ULZWg8jt$ID;iB|I9uAc@Cx0b*Sax2`5HXmqnnIS4rY84o?HN}jM8{vuX{+wMov1(vC$%lc_&Ko zjQy|pdZg!7DQJyXyqB*A3N0*11m0DX4K^MMh$|FpKvb{R*mPe_x$SD4VetzL3lG*e zPxibry%kN!F?OAwix6-$9s0$X$Dk&;RdP&nD~5Tvox@ggbJgOXbV?}#9u4(xK0m`` zwMD5pN3^B7f0W4Ql}|?fSJmy$LE~e7%WS+}o3O>vpa$$;$q5Jy-azJ=YRPDfu=&2m zhCIYl42f{D7r@x{v8ReH*>K(ARBdn;u3ujk_hq4blP;GqUhPWHs*lv(cK!fvjrQA2 z=8JA^zdku*=KT4c9yaT7_v!;%YexcBp(1gPX3iHF%!F~jHLkAG)IQ2&Q>eks3zEA; z55b?ws6QKV<;qu)GV^`NNU&~N*QfKynnw7{_<%%nV?(hOXUNd zs5P^}LWL5|t1AVf8fKjWffJX#qTVM~fv6E@yXgJ2ZI?Z1wWdNky7(cs)<~m;7`?X*stwtvG+x*E&aUk5 z%qh24Ow;WqLa=4}@~FU$!<*D6(#k2ES=eMku*^?ma_J1zXd+&v+-nYWIw-uhpq02R zoE`5)reL4l`ZE+w@uno&kW-x!(nF!ciAPZq`99@76fn(>v8Tl6Mvc>4kT864@|jKBXpUFcER@GfK7k3-=FubaQ5~w~Pj7u$^K_M68oeL)Te{@S*1-Q;t=_ zk}*?rIfzr850)!na{Ly-%v8Cn!}PYvmq-qWQWWooj7=#=Q*lMRwc-QGvTxxpN4E`# z_w2blSBjK65~}H%Kp0FdUlAQdnRqK^d3U?-9lJJf5z74Wa1MQEPXt{Ip-!j2j%It} ztRT1dAfO}q69@MH>8!E-J!`I2lLGDqLxs&++RK7!jEa^_!+O<4w5&#!O@k1|kfPzU z#sE3La+^_m2tf(|=UT%COX|b*AuZcxznfs8x>JH28f>qgOrhZIon|fC;fJxU_q%Xl z&-9vXA6Hym99bY8HkcwP#0{}t^4hCMrSe@8D#M?7TpB#KMVwKTKFlB)E}@1tOiWCC zK0$D0?~NB*2X#xL36PCv%-b<@*UHQ(VrZ-eJW zm+K)pzYl2J9}kSBxn?obV;>#l zg(sDN7Q;TqA|H>#zcmQhZ)uO>@thP9^1N&yW=|H!!BYEa9%u4>|B>`zsupt+UDB!Y zV#)&5Z2CpF<=Cv$q06Gtp>rI!H{n3LNvl;AA#}{R!iRBlby7K_k91OkD+DhDdmHjZ z2|Q7gM#y5s8o6-BY4KC{M9iVkC(88WVPJ{fs5VrqYc9rljeVf#U}$(w<O^us4y_byNE9BR)iF1egI&8I9pA@Fq+ZimgP;*>aB zJN$@zmr>HdPh)LxA&AkM-neU4?IFQ+Ua zys#vIMInIRpH8&~m|u2GH*u98D8BZ9eBv{l78#cRFdOLgRJfx6>k}_n)!+fsO7iJQ z;}{hjV|M<&XlP49@D36`mF(Q!GM4$m5toyPl_fx~uL-PKD)%aH=vQieyxWc-!=<1! zaM4YyvVnjawf(ey^+zNbq0QRhYgdCtmzQm!Ipr|MF>ap~j+Y@^hy<2hxf?H6&U6~6 zwA=ci&JI7OG_YACa?<6RP?-l)xC=F@Y+7QA5B#(~c(t(4C|gZlE+MUWGjF<&;F+-7 zPGPY1S`SINwnRdoEYJu!uXe~cwTPU@TQ6Bm75lpLN^cD|CE$~lWk()8)X}z`$q8BS z&g6X>K_RG0J{IYS*7|0tp_96}QHYJd`nx(dRxNl!4toP725zHSfZf|O!imTc%?zx# z{$-iQ8_*GxM?VBWzVMdnpH3NL@<1|6{zN>zj@u$eNu_)N8ULB}#$Mp*9u9iV8pDX) zQyb{iVJfI%cmh)E(d*fpYA$XsFq>}TaXfXnMyRld17z+95eNS3))F|KX+&QW*pH{W zT$AffyiX~z!86ThDIOFdH12z|EJi)#XS7#>5A@*HqK3q=fwdabdJ1W4O;(24xIHDX>1wdZOcv|yFTw_ zY0me=A8n?JlOFMs2CHBZ4L)4B{^_L=d~AhTNW9~$^>fv3dicXctfvNpa{9RJQJvZ5 zFSP2rc~0PUq01cfAwmep{zTN;0upgbAA6&QYXwZ37PqDA_e>^J&bf2ld1`8CQwhdwHPb%>SwSyKmWSE zREZbpnS$rPB2ZJV6@y<_9iP3rIx7TPmEpqI7IB5c!MsH0Dm+*2t;^rnpP|&;BHE_y zfa#-j%uDKjM?C!J?xK=^^yd;{ncdwfL5YPZXAcS z(|CwHyz(^Tm$Hd#d5Sd#hd-)7-hJSBYHoOYYey7WPr*~v4;&mNA?dA1Zp;$}m zF<8j|378F3naX!pWAH_ZSo9N@xgtHgo-a9kp$784aGk$8JAa=U4(J384`c^#Vqu zTwQO(tu0!DS$VvEN#}J%|KWMWH!EpQ8YU(3YrKqf*#JR5YPiBi9IrIC-2j8c3iXW= z=?G+1X|uECi&0-jvovk{107*o&1OQl^{m7%P9hJaH~R;#lQTkRfui;RQH3%{mGHp{ zskT;p0EYqrd9Ce~(i6h+n(BtmiWsRYwO!DJQe?^|CU7>TK9UjgjAS-@ykP@Vn97lc zHn@v_@H#!>a}8~4`iW(&(f$5}wRhpWu=}2debjC7KrC8F+6yje17RAox@f@)Cf#f-> zZI0OthCe*Dgm>=%m|7mr*CMJg)kTc~2@ZFAvluozcCUA-zi`i1rwd~^D3W%z+U!AKH&gTa3lJR|%h1|ebckr%kD$V}V)*F$e|n7S ze~CF8aHe-{Q?>it{k&qZp<%~NkCQ~tdbY!EGT%&ALEk>V{z>z*;AMWw%m6tf`}uxO zq-tDLE&57VNF9y{!4>{4~fm?TJWA8aq(A z6Gl+50;5JB{Ln6&$<>zU0gVmbe(>AX9Ip5PVMJDR0NYt+THK026P-5%x zhByzbVs!|peSaj?V(B%I@hclV2Db8V%iRDKQRbfSlO#5E}lwns7e*872Rl zo33R#Cjvd#OB*}xv$KGxvD=$hRD=2hUwgvkvka>Da0BGZ9@hMy?$oZwf9}-M#()AQ znZt^6ekuC7*NWKbF{Odm;B`&MeXqSg8B|;G6ayHG%x;&)4Rm=1ox|rUUO0p^z|?N;0Bs;@z_f|d`p)!T zlGXBh=i>Rp6KmD2#E4cmkGoJHn^9FYdT~?>Bou-vXiJ>Av(&CK3;+{du2&z=t1Tn5 zCRS>}Q&LAn<@ig%0djW9U(;-ap}I}+6Rtk(%36}HL~V6@95`Jmv~{M%4YeX)zxn5C z1t{;lx%7z47T=qGYG{+#qb=Dy0B+O0YhG7&-kb17o?VOfICZKhuMBSf{Q7T5 zt8f0V|A+#3lfumwd-qA!SCs5$8+e6yfZnWi2;H z@>mp?7J^LVYk1GNKRnkR0-kAVQHX{>ot_q+55<@jwuxYKI~A$%*`Sz^9XeajDQQ+L zSqC1yk1QOoFzcjqDffOx3mevBpuGq@*2BQY`AGx zne|HLGSL1Cm114$L7O}_x?H_-HRG2*=$k?+3*cos{`NrSl~CN9n@W&>#%$}tptG~R zJ{fg;d6huSjR~Z;ye^PWNiR?&HsOjc!m4*FvTw_^dM4`S;NaM{86m&YG1qzthw9`4 zZ6>iHx;u+*Luzj(4z?!t$)*fwB5q2cSNn6+V?iLkpO+@w)Q%Ocep&4hgS^SYSG)n4|t@KDAE3g!-W9fs;f39?@h6jho zlPc~B^Gjhyk(y(iL14Y-iNCTR(3PKS4M&)u{|hxK;4bn*nNQA~HjI|VJ+p)dd!IzM zPz60CRIx0E*#a9cvJ_O@(CLuR3zQ;YlO?*$qgd3KRsDh7NS-c>qRyja;Z=(*oG6Lq zh_qU(Z_xuEgQYBv-bWOkA1n?wp}w}7EDg#PSK5r1x3m)g;vUa}$fi6~U&D{Fz9a7OrJxs-ooTbOm?G=knw>%kwCQ<> zCpw`6i9MSdOAp}@@AVJ+m1~}b4$tyqlSYzoe!yq?Zeq7|&j4UsX&!XlEcrAtD6D>& zWPD!>05(?1V3B~m?(O2dFDMCEKv*>bxFMD`%%r>bIfUj(n zp&BIV`P%mxnq`0+ig_j49`hf`6!$xdL9bX2p`V3}Yez|(B07ch*)%&;Iu%1vc7Mgh z^WVTXTj@Xd(1B>J`EQtQ{p&&82n~G8Nq|c!RWqLUwOdyLvoHh@z)1k^(Q*;7HO86; zXw?I78~%--5oyn|KiRVcQC$$jFa*El;qY3jCb{1YDUpVj0(W|m5i!2pQ9-kM`glcK zHM?<>dJ;JEcyYzpv>CYd7hT^CX_MM+4JZ4RX&7Q}{CHnE^!Ig!=8%{nYMuGPyqNnVrP^wr zUNgrtGxoN$2Q5>NjRyB)GD{z(r#KT1?KXzAxnQ&M*?^J&Nlr0K3~d0=BCYlUXrBS3 z_m?B@WsK}mK5Qnp4L%9q_W;~cT8YOk&QrIF9TRt1evl#N{i-(Igen$YaDBWgt5#pI z`rW|~d3d+eGj=e@>+o2x3{>^T*RAqhuS8zL+d@Ff1slTlI}#|&m*iuDFjnzi^*t@@ z{hUoDzBDcHq3f0A#5uxck5_INpxO!IH;e4&8fjr~FRm{X@H`UQU%OGovVSSB(77{# z;)Oh(-~yySj8!H(7TT=YK`h$+9+$0Qd**X zTm6H|EAbmBmbCtp3WvxneNKm!)Shau8A3;fklvpceosOj>Cqq5pHQ&;L|jfCziIl- za#oaMz0lHT8Y35QQN$Ac{P>|b(#0j$T3%ItiUlpxgF>g1RL~0}quD{vJ9)tEH`AMn zU%+h(G$qTx&|w2)*Eghy;No5L0<+EnDOYx3QKY2+;b2ptI^AA@I;+Z5^{d8ck!43} zG@6MXi(k)#&g#u;r9b2MC&w6ViY9D@9DD8g-TSTCQHuHS2*X{wWvky^2yud$a63^a zH}h8s<*ldpn?P)3D1pnYN^X>x8YB`gZUDX}qCZ7cDa=mh&{(6~O@Js>l$JOxK zB{hpw{SH#8rM&V^*gy@6Pl(ufH){)8W*V#1H$~!vTyy6%k>x(R@S2IXuXzV%zNH!9 z6Op+Sf84t`R;fzk_^@clHntGzr#~ZJjm2+92b;VR%#w;i!~?b%RPk`t7iV+c6msra zXm>hF9&_s1vF!tYnT!9%j}toim*v<;rjdPF-g9>5h-DU)m0s$KCHu4-7X3(aGpGeW z6oh;m_9&^*>n3;-ajZ?0F68(C@+L!lCW$mW5e5NpO4!T~w4*_)J_^$*j%ZCPV>S{_ zugaoQ`lyw$;bL{wb~o10lBwr>0KYEC&#=zTs#g(Nvo~$=tWGgj01uEWib|{*qn304 zq&Im1B5?Q~JJJe}6Qnx006mhZPFF<&SVLwU#-YC0Sv{%snnV;U@?NunANK-zDSUFH zQDQ{aj@J6BH6LSu=MZxYML$i%VL!(k97XAt@M;`5jawRmm}L?q#jT#yfR8 zVix+G-P+z=wBA<**Sp!~1Jm5TXQ{zYzEE(-5VGmNM5<(rQ&Q(Bv^blJU!(PA;jo2g zFsRXV0lSyZv#3zCm*;X032ah9p4-WIn&n{DI5TS3CT}9S8_|bD0On&+CKoj2;05R3 zl?!aoR%Ibw_iPRXoCCWPdo|<}{I94qbJSVAuFnlVdpWmTU6mX2-tL!^!{vs})IVYhRkHH7_`!Z-j83Z^ z$^gJ5r0xI-I{S?23kaA#_=OfLz|j7^4Dbwue=z3?nGcJd^Clqs;*;-Fd(o5TF3)lJ zgid8wf>Gne)vUP^MPCAr;QYy1iOxF(<;jGXckmmFcseHWc-x!fLjzpe~ZE$_yZF!YCMD z8aMfAq0~FZQ`yNwbQ4dW6Y=>T9wYGCd~&9%h~vc!t;2}e>mEf-#92QyV!ppX#C})s z4*T?(xSvQ*=#K3n?_s0Q)h>BkIBAkPL!WpE7Hw6d#|6=WsJooC{oom3pFP&?)DzM8 z(e^q1tKF*NMvJBrFW21DUUR*F&eGtaFV@g{_IKL#P572<`)s3kl)$4lR`afB@5-+! zBTSZXoW*EEh}}Z0`~%cwz`u0G9k)k&N*HZMSxofX2VVgWyTR|t+EfSwYm3c^7Nv`R!fWH_kIN-q_*4B# zC=4CAklcLKC-FkZjb+7ETGNSaoP+d091NO>VHUY9)Aac@zaKtA{WIL%cxYyAkFi2s zEtXl)3GxP9i9)yM%rFRoyy1K<{;zJz*uOVrXw&EGjB$;^-a%Ko7oLX2;Gb9b@8gVo z6g#{I-EbwN_CYngIo*?B9nY4F=EP%n+r_on7XJ-i~(MaF)-|6kUoE@$-J~F_^Tp| z;Qk{+kD?hlp6PhVnANeXO+U`RtGmecs{i)DKr%D>s3uUsgY|A8Oc z;I;FR*LHZ&67fAyq)1ooHN^JVd9u<~_+Spht^`z!qLjt=%EkBk{49N6;A?*I@%UF?7ka~e4HQ>U5NdW#lKB3)#CHiXfZnwqk;Tv=uhF$h% z)zoUMBCnAy&3rlPFbYxR0B6>H|+E?AXE18;n1f~_}wA?{BXdZe1 zyoG^N^7^3r=zT!MhP3C=DxncD;>@kTba6z)<339>U<`c0nX*B(#cuQ8OoSW{tBE(q zYSDjtL3aFaFG32G(_{hy_6U}KXd=`-FK^DmT@Htz3%OphKva?<Eit#KYfAQ z?x4H3J#pkBd(nQDtk6N!k(ETkdz~Qg^?k7@uuq8(JSp!#jb#0DK5jcvsXD?$z$g`b z{1Qjh{}yFu8m{x@WP2dt+%H4aJrf8xeVxQ+h<9K3bmfR%J|Cw<%mY_KA*l?%y-U?b z-P;>#P+PFRw6!x-pElrmkxrBVFE?sbj-n7R&}7t5A1zI36Wrd3BkoBe2QaUuAH8Y! z3`cY1{&R)y+eWZ+_$NBtjRnC^e0H}=waX2HL&Yu|_||h{<;I=GO0Q4cb+E|!p5}AQU~6a-&#`w7TFP_nJ6N5whU2U-I=KM2uKKpD$!lI=F23} zo&C$xThZf$>F2Wd zf9(NR*`um(8yuwL63&TNHR-GrdZ0 zyAB=p*-5o(x=N8%@VV9jO_;6K1f5Y|=2eEipeycFo=-#Zt3V{u5yAa#T~5F8ec*WG z`IRFagEEU>r71VJ*({_6u#HPM7aww*@Y*E)sI)2n-% zIMEN1lidYp6a!T#jNHJOTGc(u9ZZwdI}^c#bI9w^?|AJ&$)uN?-0%Vq#T7gz16UwA zFc%K01gwuAEUK0xYD_15m^6z%fX~~)lZMM)8y`#`HLk9`EbZZ7=-6^VYsaH)Urz*t zyF)-T(=3%nTcLOe-O^+*4hABkOLx1mu+NP6&ok!xZDL=1UU?Q?UU2(xd#+aLaiZUo z`@0j~AExV1)W#OpEVdGPH~pmT&tZ3g=f=VBn)`o)BnH?82fI#;?XG)dT~}W5&k;JE zQzo)S5=cX2|BS_+)!P=^#jIj@Kl;D0nn?hO?Eknbqrta#cs@7PaCJooU zvSZTD&t^5GfT8`T%>8)v4|?Dt12@4HKE3?S{-ayZRg{p}F3%^MElB2~Q0d_M92`Of zSVQ_pVTRBrLXO$Hr#r$fSN{Ic?{J`eGQPT=#|Z50Eps8D5&TeNdEhiNH9t?OvnT9$ z7*8_KMKC)Uv?8fT4Y=lAH~G}&o*3V2&H^EvaYF{*Ik1@h#N52%APAkV-@AuE_&;%T zg#S?N;#A2J)wuDnbLS^oF}9fHv3~ke86xOR1ic}{?v7^+RDW~ezlredAG2WKwN+Kg zAOa*ozrDkz)!vLae0pW+_Q(v)zP7Vv;2x);>UKU_=~gQ2OV`NoFul2SwXELbI3Y$j z&d=lFi6mSddd6;b`mNQJbqwXzP7{<*djDc0>rZI+KR*vp&JZf;UGu}9?X*rLbIIUx zO(b5sYK+=@AGP-f` z1)`J-sb|HkDaDPK+9Ncf0lTzK+I%Xp0-uY1O{hM;Of8{;vf&0t#G*#^L%hpn;Ignu zOW4SHz zHiC+vWnc)sUSr8G9{L#go=n}K$)|}#GS1%W`ws}u`_ioO8Kfs1-?ob;WOz&}Bq}V- zztU`S__1bz%Nq#(JKKSi>x(Cg82**=D>q-(y%=4b zpX$JqV$kW`rnz_8Cw|x8a1m~G{fTiC;nBi@>$&iQ&U*BRUIw@SEGCoIp#ejfR1R5X z907r^EOw48mcQ28Q7|8IBAX#eDrZkrrTLSZ#jWu=M`kQl=xe7Xj=7vb;f~&3tgo`E(7;(b#G>=;ED-el>|QqG;86j40Euh{kx9&DmcA33)m~JNjXgBbcW$;XA~N zS6z}7q27V_=d#}`kv@0x9~0BDVcBp^HbVC+&||ykEC%W4og`9tNf=(UmjG-=z;Q(U_?P_RiLU@Gmg#HaA3?2O2EHL{w^6LIUac^)carg)5@7AHBpaS=Fei0Yle7hu^?u!% z^A82hczxd0JTV2nn+tM1ZIlxsQsV|9y0zZ;O$_|m@G*^Z4AMt z!tQ#`*V4bdw-#9(&{u0erxs(nGAtEIF{|_@ZnEUcDX_(j47pUm`)E%hA9Jqr=y2<& zl0m2QH`Rf*5iY@L5?Wczoo9HqOCLyUPi&I#&=t*{t!H9-(?!|clGsw1q1auV7f>vv zL`IF+)k~E)DP+IR=S3N-@7F1^T2J8ZfI*^5A_w8PbCoXSNv2h%|EBRFf)g;$K)Bxd z9AG-F$W4g(oHL+Q11&k^r4otij{f)W@`B)=tt|gpNGhCkvjFMhR506!{4C~q<0J`$ zymlv+7XWp%qovJeN%q7F=!=kIE#$YpX}KP)VFcZPKjUsc#%#Eg?%ZpI3SAf7<20sz zbL&x7MKur$;yRZa0j$X#DnGF{;2zl&-D@O_Z70l*}{`Oy~Wekje{Mn(g{CGrIf9kJ9KE@xdZqdvXupWAk zGw36%%jznFp1j8k=~v{1&FU6_csT*pgKx6h1OiS4n9!N~@7>r8nlGRU%XQBd}k zC}OnkAWr6Oce z+`{wF<*;B-XWv(=mf$jd-n{QdH&}(C*14hyOi|MXDrpi4%v$qGUYEzu6G~L2Y{!Z< z0)IxG-~nC7@}Auvzr8$R7OdTq1k(Ssl9sM2%%;5HLU|2-g4BTQYc*ssRK0O~=#Zxa zJH9-f5so7u5fl(~YJHn$R!vS83!W@xJ=iO$d9Ll6U^e4@T4-2*+GTi>Fy}tWQ@jD# zjE{E>vnSd4e+5~uc<34l_ch6NV~b~Nn-2|c_g=UvY);GTPKdMnKpvKuaMuiv%UWA~B_L>IfQ;bqJ+M~1C+MF2%q`_e@su=3 z@eB+b9vM0JwVunWLFU$E?HOiFeqWH&*t0!Nzo>TI!sg6(9i27PAYfV1uhh2ydal8T zOe=Mm&wybM;F}-Hq*Y8?_!ONPfi#)mf-vZDp~J;#_<+JGZ4?;1m6$1R|1g0`5400E z#x5*L8k)Y&p8%BW_>huvvek@b{$Mh)k0q2&ZKFVKhb}nc$}L+sl~(CcT|Hw`B0-)KV2gDH==o#!e1W6dB(7T^shil zBl!m|(_}v6w$UdIjZZk`djE@xX*fks*#(D0L=uaIe7ZS9Jzox{Tnkjkm2Mp&&rKe? z31kK~xd;>Vx;UKJ_LB}(rM*8puaEoUxR`vpK+N})rXB44!e8IGJEF#Qx*OZIJq5B9U} z55}!A_~e4Mrko}e0M&$Lr_sCD3BAjEscapsf0|Z;&Dg%eOnJA`O%#Sl8@!EQKHZ*U z^E@;$aID;~B%kr>$7R}#W&s{(TJ|cb!kLE|R3KUb=o6!fE@PphSVlW9b939v$<#aV&y zLIdzxICTJmAt}xYQIY>yx&CN}=U4QfIiA4Tr$KVwQnL*uK z!UP5*O&0_2s1{m4j$4KX9j&ob!#pgZjzKD8Y~&1H$Lj^bQZs9U4h+91m))nMzh}m8 z&xJ)eWgA5KIcYT1SdV-Gj5Ly*W^K6`E8Xiq6?aOFfWQ!stM%Z2+KEe7Pf3YyQcw^a z2Hu^2MS&i6qBp5r3aKXoP3uSUH498&e zo%+664aRcXV(d>@y{ApcL(0TSZ+M`50-l&rUcy5CEDe$&-Tz&8$290wl`V`%lk*lhybW2_iG>+ z4bhS+v0OTFWI4F}d{a;$TPs&utt*rDiQ@@USAKkJW5_}iCW*yK4=m)KZIK-S*uS<^ z1OD=YQoX98vA1<5yP~%>cJwD3!m5gtoIV`9R-n0kRoA<&1e@HC6z(pTbHSGS4MM^UPEKR#Rb(9(Tk)J}g>f0# z_gA``*M9^lxZIvSsrGFL9|%*ogFusNdzrgVXZ1!1l*N&fv6hBlL|Ah0lT2av0DU3& zm}`AKBD&td!jN*W!Q&uSKB)}4#ZMG^4HRi!@Z{vWD4AGY9I%b7zl_?w?r^EzeGhOz ztZWtq6VQ0Roj4rfFhCl8Z<Xy86#!l@@=VdQyfZEmXTj16@AIc^$R=5*w6aL%=iwFr!(a3pP5vs@0YQ!^MDK z-CRpt%<=}g5-+TSed2*|JekC@9xsB7W0gxRe@St+>KaZl?fG+au57rJlM$DK;E|UU z@EjF8;tIR8M4oR|QM$8+G}&tjJ2(?E$J z`@l0IfQgWQtmz~-2wLKm#}<)1%WN(Tz^eM}zq*=B`EM$05&d7F?d6WEgZUR|zkBi* zXvYCS+i4-!{I`GK(L9l9VQ0263VE_lzdG^{SRH621%6|sOGcB*-)Kf)Pk@lML^JG3 z{xrgQ@Dkqrst&%0C227Z=ojA+cT-k4ZW+o-6$)=)HgnS}2C-^p31B0-naDTQ+VmBrjIq_%* z2}HDGlZi+=udyvFZB8RZ6IeCmZEZ>{v|*Y70K}%cgo}fx&jbDJ_E{|nQvy1GAqur( zuJ5uNgOHrEv@!MV@rvrCLa_5Z2ViH`tW&)Y7kYuC?;Qo4=|pCO)N2bBwLWJ4I+|s~ z5z#sT@Q1$!h?UZ>3BY&dEP6AE>e0{a3!gE@cIR+3%W4Du9f$lr0ez$`WLMwY#hnhD zr2D5y+xwo3k$Yv^;x2DP29A10s7V=2%>8~=?{wrCF3(46PC=$dA3CnwL)X(O*Z*x5 zPBf(XG+C7tg6tzDU{1_S83I@(lZlC3O&i;sPh{Pz^72!Sr6nNbaX+fQ*Lgq@Q|H>U zb(FICP^<=`TH8=kDJw2Fbr~qk+LUG^KawB(3j*^S&fl@H>wVIXPyU)EzODX|uV@bj zDgmb!0VU!v&sKr3FDF+9qucP{5>U*cT7@x>P@USZJ-LfC-}n|;E)|q53%)H%7Jv7Z z9&S4zZENH2;^J6H`#SO|ItC8;IHM7KiHyc}rY6oSb00(6iK+y2v1z?t;$9A39_-Zf zwqE>dLb}%L0<749852iQDTVHu%;&RJ(5ZwgXf8 z@S>Vp1eQP1Y^;*EU(5&U?)y>v6n$85fgqH{umH-z1IhwYW+U{mM!XvxzOyi?U8gZe zH3OrDo5MCVEP@U0=l#kjM*g?gDcWU5Di-l!$ylVL8mJ{cAUV6fS=8gr5$5nAF<*>a z6F}Ko9R}2@u0&QDAg3c2>1qu%`)xV`jwkf$^z_Z}*78@2wl4U{9KB$%M1YT`zNepY zqn{Lze;YfqX|tn0V)etr*wq;P$11?=-o~tRf5keRns?76&vFF{mmL~!v{ZYIN42^c z7i>41zM+Y9dEBzgv9q>|FxIqP28PLKX)DPASSNs+0#G?fzT(_A>sUNba$VAYbC-nT z{cY5~aA^nq>C@&d@I(LOgZ$E3*bj{784oVdwim@I@H@JaQEhEbzIo94d(ioZcU)nw zrj%R3k54}Hv~;?9YEMgD+@0|f?x0#_(m-18QyZHSHK&9QfZ&5j$_GhcgEMrXCp{Up zazwKjfb5->9%#8ca~ZldPf7NoRJ#lxqL7vdzS~nt6>Bl}jdF?wOnfEMNS9q@V96(; zhQPCp=^6rvTxR-ggRcT9KNtev;tQ*YXVmCV)e2_>x++Avhwt$^CogzVA4}vn`2Nj- z#xlIBiKAB@0?N<&=+50|1VL9)4!|#MMN%$sYZI9+Eg?vj0zZVbzLJ7{>pY7#M#un` zz7lD-&243%AtzYtOXA0IUGJ9_K~+h3yJJNsEnt6Z%K1~g4uxUPV&VrgZZX!p<2pv5r;0Azd~C8}_v`;5D{AA*+6J{4Z!-vk&DvfyBLv!uHy(9MFuqLFfMZ!c06* zaih^9M_^?T}xMFQIm zss2uFfg!H37g{O7s?faho2Q;3K zZ9Z!J(|J8i7Nm^<1b(j4!_|RiBDk{~etUz*h57?_1b#jOh!()j5cD>}tasax6GhfT zHOjEMi_wW~6*IZw-uI^3^k3QW12TsuTwW%X+dXHU2UFT<4Twf6GVeZ>{m$X|tyx?k zx=#PG6tH{Y%~Toqw_lBf->z&oZE~K;Z>Uh23LV{-uD<#9GHr9%F83i5R+OvtNV=Hs zrCiCFEv{4ydFXPSzFF&$z$2me#|~;I(Ps!f@2KC6UO!#P^C*f5a-XlO^ysz*)t7|T z@lrZ$8Tca%f-d7Djr_lx73>rrR_$Lg*Dt?}qEX!35cRjd85+K@(P7VN@N_P@nybf4 zmB?S%o1Pd7aZS)cK-V{Uw?3ohQp26h6^7zF&19k{9CmvRy^CI};263CwCHf5yF;`- z|J(N=S>d-g=mP$1D)q~xtGncyy?@NQ{ zDtr6kj}-Ntk+fq*VP^R45pOo)m$+VB$&jtq-{LI#H;g*YaTQ@(VZB`aZ=mF#-^~TG znf|fDhs}tA*dDN8JV5g;P)I6QJKfe}Xo|&>_|G_Vz&_qTHwR|cmHh})v)$Ai-%IRg z&V`C3%uLHcE>x7<&a0rjuaqIZ=@|xUS8io8$-kzBfX9~eCeEV&kf3A)BM4Zqlns~$ zhoxql{Z*tIeP!sR;YV{=Fv9U{KSL&+oZ$7xdlE0$k#<*Xser7cf3r8I5l)rg*Fjwk zsH=x*Jcce=!p_NyKY4HOwT$c*FcQ!K91}Z^&i|wBJ;Rz@w{_tuqEeJ1Dx%cTy8_aS z(xpmAx^$#T5eP^k(m{k!rK|KVNN-UQ=|sA8RC+gb2;@8wSZnRQ_St8jdA{$5*EMxQ z^1h?q;~wJ~k13}vm%{j1-Gfzdf=^QGCiVAZQQt}p`bbV?UA=rNKq(dD_n9Y)Y6mdX z)czPO5_A7$Y%CUSs7DD}w%V`HBES_VIgjrwhCi+IbkoTX^yp9Z_avc_R< z5(hO<{rrHvknOjrADNe?jw+uP z-O!$y`hhv892XY1-=6u5%hY0A^iCicN~ZD5TPfANG*Ht};1yJjX2QY(ZTP|ESbz?C ztX*R6o@9DcfD&{Ho|iy(y1V4vs{J{u0htx}icZYxO7_gJBmt*fZ3~Ay;+)5nxaJu8 z?NL~zGQP&1vyANxY=nNP>m?eU7r7w9X<*e_?^JUV?w6&p{gROPKunyO62W)5Afl9gpy`pxFnx#z6SF?O1ERz8Kp=GFMp}>f?{4G zH8^NlR9=7kSsy~{&Sju`>FOZhmRMfyT>2gRj2B$_rCj>!%UesObDFSOkcF@PbRoa( zm+nhqk8Ze+fF!p4IY7Hm=o2 zDXtCtxj$TfmCcIIhXX<-+7${$FfQk%v0N{BIQD4%}Mj|6dVl@(a?b+hVg z=^oy^Kthwl&OaO8x3#(|ZKZTIqEPFXIIb#%sGP8ZpJ@rXKqZ42!WUN5FV*DUa*U+D z{rZLwQSoY?hj~-x#~=2*Z1A7}`L``MBw0gb5b^o4?RTvbjke313Id#bN$$H|RniXX zFa0~ci}k*LB(~a{FNHSKuTFgyX^;r&8TUD(RGMIF`_AG}jYRE@$bq7Sdlm(xD zJ>$d-;hQo38!~_4Nkx2YJiL%sVCcMc2qt1UwXez#oGpDz=zXkGFU z48yW8J3c))!lJR|MvR9b$C#Oc11nQV##=qk9DAsTY!gpP&0m#!y~V=kx)i3wy2jn4 z#(j>`tZSxOb6oA7+8B7xpLzNlsklG`dy6~#!t!@}L+Pjc_VD6s5hrsD2 z)j)Sa_Vo!X5g>6{|2iJoZV6#^&Cc6~1Co#`38!Vne8Zescm%!lM9D=7046s{T%OKV z?}$Ip4i>l?->>?G8Sn*TS-sbp(4%Fi!)s@ zebe<|B(`UGgR)s)XlUEghSJypyMdCLmV#3?z_ET{6`hQgG9~4PTAHMKLa`Az^Jm@z zmMEwc+kLNbY>@;fqv5#IDvSM%S)vYJufRTuUhGl5!W^$r_9U;#Td?IrEBoa_Zmz`{ z4voV1-YGQ^;LKtVIQ$UMCpJTysh$uNM#(K(Ukqw$jJGr4NmrE zfgO07SwvYnbkIwBCF7aKKBS?>lBP|js_+ZGI}=UrGb5L7mni)dSCZy3>O11HCy(gttHzeYfb53JrALi%ir{+-U z3*Qhi=IQV!Ph7joh8G*NB4~Ysd%^T!^T;!j;fp8)k0XacxqA`yV8bjbIlNxHHg710 z2DAG+#*2=U*R;>0U^I|;_Nrey)ls;dDOgg$ayAr>^j2-y_vtIpbMCjOxOsmi=0S-Q z4ZCOY^5dP+sqv%E378nTk6LIRp$Y0hA zjdg5)x%aN@?buxDmr!v3V@6BuHxukcvHaC5HJ{DF8CVe}_NG*Dj3Pf4ucT$1 zwW0zzq^>grdRC3O#ceSv;Dfb?TimKOucAY1)uO+IvOW5|`|c-Gu#r{r?coH?Y(*B& zg{dDD0?>W&Qq)cer;R)~I!UubD}u1p?*l7dKj<(GoPB==Acc=g#~lepPUl(&+z^g!BO(9Cuv%&`vYw$~{pLyRBO8 za@Q{F(vC-sxNR2TEZod38cFXkOm?@%&LvKYARGE<_0Mlx(^hG6EnO70QU;y$DMF?z zK#e;*6j6PHNr*%YtnG@^ExP0})i^_(6AG>Gas*pI1w4Ncm3BQ+B@w&Eo?=?W^k>6> zl-)JEvk~BEwEjf=kPY)bRvz)r9Tv@f9N(~hdj1K34s z(V*hVYG#i*_s6OO90?SoBL`+2TJp6YadxNGdX zQL87R`{GDCZYfXUZLrPuC)hVr33fUfRJkP2FV2s>cs!8HR5{t`tKcZQt(|ith-T*b zwpVe8uuCVI2)J1BhYmwDC5>bz?@U*!jIor!P0*aU0Cms#9EhgkmN09zt##R`oTr;x zk^`F2o-1D(Gc1Z99>}_+lc%i3jhQA(wVJ)Q3lm#yUI*ts z&!b&m3)&V90y`u3(9_yExNQ}++t=A%Bv8{DPf7Wiw}h$kI2|sOAWcJ|FpCCunSFu9 z+uw0`X}#ej$4>gpx%`=p{<}iMJUH#Hkv32XL#qi3$JcLin^tHP4h`nrJ~YUwby^`Y z-p_wj)4ai=h4FG}-UY{F?FPrP%v#y`+^>mo5qq{3{01bC^(-DS7ao(-1hUTh)wg;<9nkw*P@}(!au}xXoH-h;@ zuC#TXEc9?13F;EVZN+_8;yr+l6;Jf9HAOl-ecYE{>LlrbGn8i~#|U70X97x1`Zsvb zec*-dEAuZHgsuqANOEjrwizAvg%t-@@;OeDbMYp!GwrsG#pQ zWTXxo@_i0QD>PK@)*xPsuy~6xe+;Goh(Vr~IS(t)w_7#n+%lvH=|o5nN8DJob0s8k zaD5V!Tp2wJwmh_fBgj3dM_MGQN%n4(#c#m5s?bMZ$4O;0tKJ)dAxRj~yL%I#K7CWV zsuTkj8jWj{nAGmvkOd>y16yuZ--i3-wO(Go?S6bD^Z!3vBJv_ZXC+r1U9s;@5;e%X z@mkx#{;YSJ?|800;>98~_&^OpBH)@VWz^kZim-b>zW7yH&FX zkjbU9$w5P8y^UZ_M|nmFJUU-fV8NZ^HU;#IDBGkW<#Jr^954!wKDK`C;f2r!}|{ z#6P%^!ode+T$DN774c#&k6sog3ax#aF3c@#y0ZG3Au1`RW|Aw4d<}M;i;xoHY~OdE z!fvhn`<|TT?#;817m?}044#vdj7<90?XenP8?iytt!WaFcs$%=E-**st{IX+`s&c- zr(-w&lS1y_iavG1-I=q8u(qbYX0s=Hgek%>*YSMxa!r#lXu0Xa*VpqUmoeY)f3QansCH$c%hLh zMK5(kul3hBUC8SUgY};sGFA&~9scS~fvrxF60Bgl?c$&+#w*jZJ@&ri?7YiikSf}; z1nwE3?Qzr@zalQ;KL6x>Bn&0Nlc1e9pDXnOSM%$WEB5bj6CiXsl_ma`F2hi zfntZDGf|+*K8AR2GJyTloWYr=>)$-j*7@_0#B;vOf*1wS5ySPlKFq;56LjiilO}uh z^1FeN zx+9rYHE~}Su}SNT4t(=1Cl*X)$=tY8$SdMDO|U904Ew1)+-RY93-j4EYbK5|oiM~b zv48ec%O{yh!d5S3X{&((U2?0Iw$wV0jCVIt_x9AF+OK4h)@ev4{ENer0!#E0^lmKx0R?%w`l zh+vVrE}|c6Oc%!}9{j`kB7v*!A_$s#vpJZFaXIZ`WywqQD_yf24D z?Ktn&Vn30@96l(upHm&n&#p4R|Np6!Sv!sEJH+xYUJjBdVJ14cg=T&jKKCc4Z3qdUTonlsvhR=3pPWzumf{sgzJ*!`L?TdhCfCu- zj+q982%+?oxY3kJX2M%NHGb8iAYOH*udUDjskd~d=560uYO2E@IkhVlfvD|eo;&%b zmpK;qmX*t_$G=XwSq&*#?I^C?o?AMH-u9t8AAaT0#>!jXU=KfSk1B1C8tq6ir@DtD zm9^l;E=F9C(!vYfZ#>7)>;5qB@6ZgVQTz;&;y8*2PY#7+-Z6fg>6v)9jLD^z*EI1$ z0k>eJdnSBO&}pBuUTLwvn0?2?mirufE<9I@czZ>P-kAhT|DJJLse*0ydv(tpSFD8N z%)rp3niqp+;x}BhJM2ks1=rT}cJjj;>wA~-ie2Z|5m8>d{T8GhI(mbO6giTK2VHoH zx9n<{$E!@ai6l5KPaCfoC@p9*OIu0tns9*eRRT#=vQSmM5Jm@FFz%LXA^}}qfV~|P zofwyQswsW+9t=>pp|#h}l);*;HAYBbHIY}?%<9t~!^LsP>H)!V!YelY9|Wg=$mKu( ztfDO*Z0|186sNoS z7v^)y+aEK=e*rft^KDUUi)IeL!lQkwT;}cgcIf4tkeBUFDGxtbU%JJ?0d<`VnTA$&-EvT&X+XuZf$DxSM|WU8D28kbYBj zrN2X6pT=(bdj!Wwhw)x~ga8fMu3b;br}67?EJOVT+~alb?%$Fg982Ra)3Fay)x^jC z9scE%PPmIlegYlvxM}i6=-=C*B%x)Va1pQd2e-V}Iejx75~BqTF5?|X%3CbQkS<~< z_Qro!%jrw}Z}s*sKcM*6sS2MnGs@k>_m+@);IT5o4K5(P2!^l?ajN8d{|9|Nr#N}iC!b&G!!HYaFTWmxt})t0 za~fnuU8Mc4;A)9V%T8fECd2$}k1f2_RySFY>`CHZ(wQB17f5hHGYI_m`SUsdfi$}- zefe&PN~;y4-G494pDHJ*#^o#O$!+@g&XZ@L&YRfjbp&HHr;VD1M^ODyt#>rL*4OJV z+$soQ}OiaL7naIxsv@#i}WS^+?k5>GyFh3_td`FBb|L?`| zME2xCUQLnzW7tdS1dXsmYxwMt@#&*fz_-TO-AN?=S5;`n{3UJqxLE8% z&_62W{~(i-fBi^x2KnsGBrjArLqXv5_wy9#H72X*WwU<{w5Rwg{Ke4gsVprG4CFHS zR+V?nmdERePK;Yo1CIc~Uc0XHf0#y5I0Zojw4Y8NCG*6;5~CA1W43Re2~b295$pj^ zYm@zpfiF=vrsiM0j{XiIc&OQ0e*6Dkk0~e47R>K03)(dQA1mq_K5hB|xDXH43gHkO zpyA2mz0|J#N_B3N=pQiW9n(|->E;1*B-`!Y)26B4709tuYt2Kf@{fQaEKF7~@PqE= zZ}3(uM>qJ+{_9(1iURx5M&iAeI@QXl%s?1?4w2=VY>-3pea(`v7m^8idE27)wDkKZ za;i~QMdH&>)QmWeoGKNZaeMpGz(;r!0y6>Y$HV{(l8LxY;9v1=)MsE(T3){sMgQ%) zKL&u`C8W+j{c*+nrxB(t{Q3P;VNZn|f1P`ICq660Pr_%X;|t2V6{JTw5nkA*Jy*Lp zqTX67tu|1gjI(#8iJ4wIdapm|_?-*tHW$wk#}hADlyo251n&N;&oG26(d5OS%GOK; znBwb8|Cm|+V;gtP$$(M5dR4Ka9vp&B$UoHWLm(Tr@G4obg0PkpE5_N95C(DK~9}A0Dc%z z+1@_QoLOpZL}?MIkN?y$!~31@j~0;YZYZ<*iFuy3sp0vHAQbEd0{NTjz7Ris$#vor zb?;gkx1K$=^}o(wPh!PULw0NDIXu*skLqCII9q~=rp9VrUBwkKq@vkSiz<3Bq^Hbn zh}O=vsls*5*fT)hpnO`0N_?|nYQx6IgLs+gp~fp3DIS@L8_Y;vLxwQfy}>EiTdyiL zGRQdOz7+0pAwb6Rd~b1x^`DVOkqg9x&4n!H+q80~i(f^aA8oijzxU>1o(Fp4XBK)tc}>~x#oqLa(D~fv-laf2tHb@S-aHG# zn#OzM5B3)LZKmHkp<3U{C`zp4+%h^>QG`C5(f##ULx_*sRwlf8xXaz?w2NqtR??0)_AJY@xiJa zqP6BFo^A0>1m7HJlrP?W;WR_|$({yCStA+O(+ox5c%so~B^2`E{C<@CNFGkTk_5x# zJMopC0)P+#gGW%S^-=Ue*;Ut$h@mzBo6mO)6^^o@wtQ9F6L=ZVros6jeRu4ITHOxM zcQjMR#ZexJlWU}>;RUpAe#_v-J+K=v&Dm$UKyRACAV)41-r@hFL%(T85DTB#Ctc*1 z4p9lxDVGX%7UWI{G#ngpo^oXp>#n;Py9z>PEX$MWX+kQ@h6?JsxXVCSG^4UE>Z_-l zS%Bh>ElU{LF#N|A5ueo*9}3TJeOZCZis4~;!nXHp^Ff?)cg{NC-W_Y`rrvg!sZpNJ z|4I3<(%`*ST<2(cFCUNY8I034&a%zpg4yZB6oQi-7Kl&W%WsZ=-~7ykX0F+h*=D2^mc#ktP3DT?LY~N{ zOIJQU*-7*5t!Q!6d}AgFJ%~6%zO}#(A}OiF2(E^>#R?3fJJ}~^otv>-) zQ4+|nttz|i79-B!MJ`%Da)2t>UwZEYcgbSC8#g_#PF;I+J^<=bT*lWIGn?%%W~ z_qiR35n(AS%^G}_J49ek=8sJh>;|7OX_yaumZy;Mx#XIF) z)Cb~#rQo5+;Vs0xlvK8ADntsi?qBXSZm`&&M{!%H7+#DG376K2njezd+gL-+x?V#P zA~2YlxsvVui&ArQlv2pgC4?((FxdKrjE_V>I_naO6iI-nKk_=XGj&t%rsG}OUhBWs zyn^}7=^S56X%uT+Z|Qqj5VN_zC1kOp3AJx?xRY8f$ss1Y-B6pg@VZcHjjoG_ti)96 zB?_5tJ(L5!;#GU`GCQK*wm#wqtbfu$vOo#U5VjpyYS6tt5@0eDr4)%*6b?2 z$0_K92rLzX)|T~v`M`yhLzMG$nDeC}VN=14n|v2uC1dY(=KBJhu1YAd6P6r`#Fo%C zH4|%R?(h3b%qeRzM5m`;=;BF_MZz=>x0*09OLNG{0L6@SfU&05c2D3}^Ws(xN%Z0nHV4iXtMl(_3+fVl9Qzkti{ zXK1IUS7#W|lf0p-o9UBOZkFf@p!gEF6cNH3V{+gdkEyh`5I5y}TWX+_%iX1FN&`{f{{bIcDctYbmfmE^}_j`=CU@fANe-g zTQxo+Yf$BIqi3n3kga#a3?v7Wle>InCEy4SrwvFMez44-9dRCZT_pD}aG z%VZ|K!9tcuPdL4*v3GhdT%{E;?iCCixiheuQK2hPc;p~`atYZTA84qXz2h2|?^_U7 zk);}F5ad_`!@v)(^O(GW3=BE%3vAFp_V(J4boH>8gqi!ONXz6C&95|GXK7JS7i_#` zq0c{EOQI?2={H5tR(bT}`^((|m(KJZ_+rJIoz|_U1J;HmY3^Th3Jx&Xu3X6U7HY}V zw}>-Ry&Ee#NcTO9J8X2%LQi%T+%k~<9fQ%Je7c{M#kWkk<`MGjZRH*bq7d#dl%9^o zVD#YE<|WYk$_M*e0j-3buwI#~8)dUsAIlRUyh|n-bJW_6`5Q(VT*tcnXdwJxNsr|_ zQ>hmIU7ujZhOHr!5ZKQ(1qRK?$&PUFQ|Myl-c_=NoUJ|+y~P?@sR}hH6Sf=+vmIue zQ`_Cs2yu^w?~bK*Pj+qpQ8v4nEXl*4<0OcZLFcBW1eEha!?LuM^-#&>FDUp9>?rt+ zz1rBUbA?ILTam!$C8sW~7cRs14;POxVtExU|!oKf~RN9=yp|OD$lT z$+fpd3Y|X^%ldSu!hehO=@K)bVq$I5=D7w6bnf@f{$~Klops1zpq?4+zjj--wkGssm^)qYiBs~SpBQ@1A;F}A9sKMQuPdZxwX5wCh4~W z+ptz3vSQI8PKY*W?pu}qd314s9IupNN{FG?HlCZMfk)viUFXJ6ueDh;V6}~gAGB*@)%uT`4tY{e!W!PSa*pG7r%7<~A_b-64@>#J z>kV=xW?AO_EOY6*CgL;e@V;=EJ0jC}$xy~3RoF$^d&gI`(qWi~ir*?0Y-DP0Y`E~E zPM+glq{jkVMMBr^c`ue#PPEsXj0UTqjBPT$3+)r$=>PV5xp7>o2{e~T4X(vGtAS&be?Ot5I z7h+WA>t8rlHO@clv33t4o5V{lohd^1_z!#cQRlBX9g&OFNK9pUXZr@S;D}-&WaPu(mMhKsw>?V=@*WmoaKcuCb^dnFiK}~tKi?G ze*vl){OAx+>JTtp!3VGDN(C|yj2-e0>?et!>s~%T|bA(glJSqEaNSg8B|(V&0~b7=3BGd9lyyT z+~k0Nxs##&5|lE{IyT*TvSxjs#><4?EBooS(8NKIh045?0g4hFu~1d;x=U9>)^-UH zgZ1R#t;x^$ZITJ!tacWH4!qlRM-*3H>d;2u4ZA(u_9L?kRs1g`6QIaiJ{AsuqD?4p zqL%wb6b!u`2iBBV**FHm<6Zdfn6`L7et5U+bQeHd*<(bspHCF!ZW3u5j+Xj%3K%5h zV^3+Szs_(Uw;l3~<+>TB0F$g3`SHL(KR_{^n_z+I63!Bo!S{6$G4v*BQ^Qmmp ziY>QoPS*c$3Q$aFWt6SO=WDA4^?lhnD^W56#y12A(r)Ujx;N5uYRar*+PLW|?p*(4 zH_d=Ow@mT#5vP{U+`b9ee5AuF3Rhi2yUVk*tYNu)#ElWko$gUJ%9 zms+{#%>c378`24%F}4?s&!#lqHa%lQwhITov1&}zH+1yV#D>I&BVG*IFOE#H;tWt! zmVE&v-MT`+Ybw@mlw{&wQ^XEUoSX3*+BxSp1m&X!)>H7kURrg*=$CiLM@CllR>zoN z{jbd&AB)KrX6zLb>r#iR(dX>iC(kvA0%0*kk}Z%ZWC0`G(HC7H1Riz`7gSg)2oP$v zHI(6G3$)7KfIZSYEeSPkW)cAbbu5~mlTh4KEWAQL1p%f&`H1C-9sz=|-Yav}9=ykP z!iE1R87NSVWdD9L$UexS;AQ$K6Yx`m_&AHtdWBEWr*tui1@kwI!>HM3VGnWh) zWJRZ}u7#1=$+HSRjnU(d_Dq0LBzJRrH)LxwFX-gd$n_%!R9P=Z$Jn60hdmXu-Q*^P z0F#TOff(aa&3`Q>6ESb2PF(CsIA0F11Q^L|oXN!b<}k?v4{|LJijALu3yBm3-_4b} z89-*IMtmG-PTdLA%M!pF@?=hkzq}9V&MT)Bi0yGz+-j?r;z9NV0bVQo7DY8@Kr6n9 zxaQ6soOg8ipLhpil-x}a^TQ+I)xN#DpaRb3gpiEt7Dl zpl=;k(mVc*zaNmzBL?6KN&^HyO}ez;>8u7I%vKMYwrB5QO-CQ?kCt(+uVqpylo29K zjwDTr?`qWCG9~Y@0x4LQ35fUQvOK-)2(uMUFwT0M@WpU{p#^^dL4sR4lfq!N8RU~c z6u_@c!QlW!Uih3w_2}VEdkA1oKliq6sc`|)@jEWZ95r_ccGUdU&dI~gO~uC~s8x1K z_R~WNQ;6#yJ;bzFYfKayX;ipNt6pK?dmA5a850M*rmVQ|0~BcUmz)6pGH8O8D=Xoj z7zbk&W8=tsmGfBfz7;3OEl+4^8M?Qk$PxEg#{sbCN?=K9q$40YNO0 zK%$bI1&RTRoYLEi;D5N3Q2-PY9DQ&bC`bj=UwguNs)8Vv`b6Cci$^4s*jo_8fn@sd z>byxwmsbHHRQE*=E!_}*Ob9)XBn0J$QLTAFim0!Az8(k9!w;6*w{L5n4t&wa5dt3H z0A^UD3T^>mO3>j!JYXY(P&}?t9Ax)%Nq@$o47)R_!)7`$hW`8^GHbzmdu*?4J-E5d zsmZ!6S*%Js&%LzVZa{^Ik|TY=rxw#+Fui0hhHcVIwC}s0keiQ|8g(2{3|0PF6 zQD6XExNImkpQ&L{K!|i7JCaRtzOC(pjYD%SO#lcO8n|ErJh0_5LoZD{h-FW-yFgs%=MgMhbXmKVp@^nY#|&^mC_qwP~u z%gnppKxX&^b>5luhbIV{KI#cRxKEzLUT7`8zNYMcpsO4O2RxuPzbf4Syp}AvS-??Y~XuU===Q^q#!3|J77NezECR;k?CWK9Bm7acY zI@`K=2U#83vE~P`oGAlZSsS?MwjKZ>NjkvKXl&{kM@d$y(!4H0 zz;102C@+IGK-GpESIS|LqEELjQ~h2tN|1j#2;Pw2MD`#Y7w`uC9scy%CgK2s=mO%w zB}~BYSD}HSap4T@Oa3+B-drFCr|b8pT^ehubHRMncXupM4^T9G?Qo6(;7&_U0*2me zEFJW?d{B8d1)#8QtoAkMNwYd$NEHN0rltup%4Y&C2CCi33vQ(2b3@b8=`F?Nt!n zD~yfG1;B5ZRv3KI1Z!hBMh!R(UX?z-*#U708=(B3A%Y~EwAVj7@Q-b zCliXIAaX?QhW-Z&PZNsy0$S(Shp$3*sKuC)x7S`dkx?29)W1n70x8__ky6r|iUZHq zPZllW$&uqry&v$6sjmYs1*ELK?!O1LFFrz^(VEa|@<$1J`Ck}hv)h$e2gS(&-3cUM z4@_|IrRE(7c|a>Ot?x&J2A1Wc!*dLp%-PrwvOE;?U=|Qjz#r+q1JX}=yg_s)3vfEz zXCqU@8LCui&8a90{sKnb3XHl5XVkBhc!61$y7vN45#h#VG_}X%kkoH{kpO(n{mKNN zLdb2-5G9I_fyjcb)JpM16SVlI4Vo?*g0?^Y*_whu-Z;?ijJ7*|iUr#w?v|w{G^;N> zoCP^PG~~G@(-X`t;X?mj-qdR3*?md&nT|L@wGTtYCGGoL$yr)0m9D=2wQuv%CBabM z;`U2wQFkVK^=$&h*ps%Ayh0Bsw_xq-^XFaO4lGwnIBtPYCf4f3XP34ddT1e$sD9)i zV)ZQCDedJ-Gr(Bed5p3KAEf`(ZFmg5JnT!txRC0>NCsJnRw@z(OtZn7Y$C`QKAa#x zo*FRI3$ndmgLlxMU!cSvz6&S167wixt@4f_kPQn?Hl_JMDy%ruW4#7&#h^AW*$+q9 zYVAF)sWR~GSZ`<{Q3jniu3zR?L3u#(FhJ2$n4gZRrkxO2)73p~bZPtt`j5g01|^Wy`2>Ly4|BP}If$0`h~nasyB&sq|l4sw^%= zH?nf1Fh*W!OKiE^kRZa*HVmDN2hB&w`|^5vg7>&eK#-&3F3!8n^+JqlY?9gDz0eCz zO{)(5g1Prt$v`T1|!mE?z@Kjea zeQ-DIT6?M}@uyQ6lda$J1NVTo&8{3U$}QnKr}zPHtqACF)1Bf3L(cwkYJe#(Bka!ri`4+{`d?XWv}%Y0AM8!ahN8+| z?n4_x>FMuQ#M5v%%-J*4D55S4W7WG7_BGxYw8%tU7lzP#`OWbgp>iKr;vV16S-fQ4 zbI11v0QLfZQOMl}iBN!5dOE{RvTXI%dGbKF>3El}y6=m73(j9Voa+RK0qC4>D{zWm z>M(gcyi($aNh6$IXx89UzX!$6s#ONbhX}L)T>0-{iy|D@v3>qO1KNxUD17d81oPOl zadVhFqN;Y9!UL~l)aVn=R`!;%Wv>R^{ym#?^u`T_UTRzrIzjA-EdVfW zxM+fO6mYGSOpyi;b{TSYv2KSZKEiP4Jmp{Pd{2vIPMSqz>-=YQg0x+^4Bx%E!V}ej zTDUPAL}nKf6lTeM>k-<0&!L^`l6_dl7vRXZXHfB4U#sS= zX=7zUG}xvDMQT!etlbayrsev{Mr*-Aj4rEOQGXHRxSC|P%$<7D%V+X ztAV_U{(2%#q@V!G2*Z^)tP%{eNqsox;D4i%Kix79M%t6)+VKSEoxLAC`0XBKmsw3k zuiVVs!KicpGA9QSj28FgrwB+QeiPr%5(4N>%|~^IYyM?V=ltkrrT5(KgOsWS_^KE} zF}Ks*dGu!pa04FeY140(hvCAn9Z%El-PwJ1i0q=w8)M6e+qLP@*6bU!o@;Vug zzC+h-aVmbNXo1?|v@y7IG67zDcQoi8a_uU&D$rew$W>SOL4}MBCRqN|oqM~)O$BtgFlKohk#J1$2`zkAHOG|m`v1Los zgT(fkRPr-9+?#zQh##18D94=lp1lQT0*0Qxk8UEBQd}A=0#^-+j`aJ_!BA3Z82Chm zhKbQFkrx``L`rkqTunE}X>P|(V8l*%N{ArsxgXM*JzMm8eVbmHS8mHUOH+bt zQ!9z%mwxvNROD}0)1Zf{o}suZMFsym{w zei`fAf<0vJd4KOEhe=&=gErR#u6H}@Tj{mlp)YrzI>{P|6D`K((t`;LMgG|M^va*F z@|@dCwOA|UT*T;LO%0l&?>VDg12%}&KeNH_bd#wN{|?xA!}6d0R17YR4%dXYP>K#4d{}$839y zZ+rHFqcOap@jyHN@K7&l`?q)RVc5+qjRlUNro5%KAsR^25VA$+m*q-hYS2cgl^klM zE6eG3c<;rx=)PzE~E>pCj+S)eP@*-g|uX_WUDOlk%MyGCKim zn|*xiywzk-PZ&x|t{s-G+c#yVyX4ssaL;vdIdPZinqd39A#LpEVb|ceY~ROmNOE{Z zf>(uJK&y4kg@UH9hc2Dmr1#%CASR=zC9$M1tS(F8`s|L81R(eiNzz3b9J3p*dIl{% zr$~~5h@9Pd7R#8Dej`Ktl|G+BcJZMc(2$!>NdK=K)t~8oEm`BSk4D~Ar=cE?YVo~( zX&Z;6f@h6-RqkYve=p!X0PRfk6@~KoTab^wBYo3Ajd?Z0+B+0@MRif1%hlkZNmb?4B zBQ^K-xi@D!9&fJRd%TyY64z4vp~Y+4#|aE2%;aOS5<)5If-P%!rkIUI^*)>dAgj%8 zLmTe-^udvFma!PIb4MOEjO#)wyss!r?3fd-@>mI%*B+Tn_zO?~-A<1BM0uWHy_c3A zl+~_oD9pW{=IAxmkW8siO-9wtE6&=0skmJ(Rn+`w&s&`WoJiRXc}^FocrLO`YdZU* z8e;A!Jq{v2i;4mB*R34j^lSV@Yvj~k2yfnL-!V!UAFoPxTHB1jkWoRs{RsXlP*!oq zQ6Uk3f=bgE@Fa2gk?i-(FkkGzLbYMdtls9{9K9U@HPHNMc`?B zjPC(yYg6QAd_B~)t*+^Ue1A^PU0~PyY)0S4>MIu+byp5S9_)he{FdqcRp(;uWnmz+ z8Wh}2f)&EP<_!1nayz>+h}LUenR$G}^})tY0U1@}kv|Np37f2Fdm>p{XlqcHsW%~BpbBRH=CETG*c4s+vlKU?wK8j>{m{#WALWb_i7(319x}G#^=2*srQyu zzQ4!LLH2ct$~R2wePS*e?`Js~6%zBd>O3%MsMYy$%NukU0~EPI2q5+-it~h}7l5`T zH1U~SCN_@S|JTCrK9*kCBEhiRCY__kST|s?!mZkEMAM>?2||oT0g5a8QsVGJYEhSd zcYv&ywF&}_QiN8z6s-!^w|0`r@@8_Z+$M+CIzst#aAp8sSQOOc&^wy)`hoczbF1An z0t`V&5hFN|kwb?}rcV0#=HW{g)D$HF;#{NA={* z*(RT?9ny*A2XCJJM)_P??aQY4y;fzg06JvL`=-z*!54R-VM(q=bQ{(k>`hCax2AJg zGNvaz+hRWk-}KCtbMdX;={?{3USF>1_P|i2X<+O6*4owv)85jQQ`6p;vUhG3@~%&N z&~`x&_UwpHw6ynSC%v_sapKv7a)pTGX|!|}x2aV6QK_OlH&#B`W32ls13GW9>h-If zVx(!H;)g9gmh4$)f&0882lqn+lCZH|%2vIPoxgnO2#b$vDY!$(lQ^&s<(9P;v1?SW z)j5*K3@qI-SwZ2ij!a6}WQsbB(M{H8`(F{}MTe_4&8>kv?|k?QKcMx(oG%$JtgHzx zvx)GfQa-!UtsbF4dq@u^Kl)~0-&SBTB}VA(CI8l&r9y3k_Tknnc4Y0tbk)ZMWp9`A z{0D|faYt*knLYbp_5*~U89{)^PywxV978c;1&2FTT#hD-HPKkK@90b%v(~`7YRPK^ zK+wrss{+(obw}V6n})Cn63JGrB@@r~tV%ylVlJFJ+AfhO$CS^2PIJ?qotx41>I)*h z89q@bQw1aYhgmJ3Bdw|wcIeaV>+`fZ^`*nPyK4R!DUfbcw9`_OwHH91m)?p2(Lp^q z$F(>CDHybEhqP=DONghLBU`69gCs%_W&C1QYpXQAUtJ3dx zQ07tS!^^NiKq?>uR6g?fWhg|p`KG25t&;4uhf8FElL&T6#rhSx`y^g69C}>5sGU_r zwi*=I;9J-mRxxwWn96gVvCc3Uu%nfetwpzIWc%Y`iOZ@u2+ z(x@F#tFB4@{sa4U?Zeqgwptcr3%Sv1tH6Rxox5QIqWzdd4%wg*>_^kaDATi(d<)Gz zjjqOay4z&}G6k6OKmewJ&^ENYx6nghcN-216Z=#HTfJtm-^X0gbE`!L?k-|$fRQ%R z%8y?48rkDL^2w;L^a{d70Oe_RCjX_1i0kre`x`MhKUF=dTd}v??HvaBBsHN!Purw; zqr@n`MLoII7>tfMM>@%KNL%JP1ePzzrf}~0K>2%>Li&s0IW-yLbyUM8t2CPT6hbbV z!oj?g0c@lh>9Z~7iYXTY;{!y?#ReQUpUgx7;u7JQ1CHtfvt6@c(3}x+>Wbv^UAcVK z(1@<&((<>hb>^Xke{uV@lGnU$f;_ksUhh)Vk!g`t`}TJ^Mmo@s0<_%$4uRg7Dfznl zwgDpRft{7PlLh9Yq^Ge?i{`@Cko7(m4bza@|97mvjpU@(b=6CYH$!@WlKi*0P~jZt`!$I- zUaGUA@Eum-ZKk6YG9Qe%tU$8`G+2EH84cn2Ca2g)~vD zfhqTg@2#GCxfrEMfhJl_#f#rg$&W7s*B?l^yydc1+LWEAo-C?*jn{-rHCZT*v!uFL zKrpHO#jxA(<5@ih&1B5Gm8F@QJqlcbfV>4Kr|MyH4YqE;$1s7}lbqNttbJDfW`oe= z4WpU|E>ykqJQ@AHv7RZvUpa`COQ}ArPXh(O03?e$cmr*n8Aq0<+6XYG`PPQw&9&LR zWT7$ct3=m6EcZG~XKH-@Ge4saWt467bYo?Yn=@tTWs}MpE2z+QD?4zGOb=9i%43nh z9fdty=(_OQnH`?!UiYpvDeOlEKyM9}3Ot7flBN~ReJf%srf?hsarsLw|YlN z_I_jiUX9QGXqqKpDELRkXWG7(UU%0r^Q^mI^D0bkDBgFrJxP_N>RCUZ8X=(J?BbW( zpIh$Er$ly2o9pTcD>zXNjp_FfkYF~2ew`Job?C*_1*b%bNE$Amf2l+5Jqg#W($(9{Itf;h7ibd~ET&Y0pI#;zU zL=MiO-~7&i{`&hY_uS=z=ju)?9OoP`+~0vBQs9`n z2uBIc%-RbRnh$t8^nDXOgD56)lV7;}ZM$tM%nZCP&P1oP156UXEzk7|oDl{#SajLf z<0vPM5D{rIEbCOijvN<^a5ernHfJPK+S2Q%a;0(~I8X;4E_i z=AtI-8q`IbXw3gv)2u}6fptA+JIaIimETYWVo|O`pJZi5LXn?=PyF|`R&YmJM)2qG zUuaC%O;P;SdnRTg@jyNumV|(R)_idn^sm@U$y6@?VM$vG*QOQDxiSZ#M>1BnScx2nZ+$2((1WN)7^&C9C8tIa4B% zB#9)6B{@mXSw(Wrl0`z1k(`REZ*4%^KHYu#ocr#5Z=CzSG3ZvSsIb?XYp%KH|2OAy z;ucD_F_<@BYn;%S_RFmx-o;bSHPH26QuWND;{oS9e5^~$CNDIeJfYoRwN zpKN|HdQkF$&rVrULl~gTM*`tV(%s=P$ofyFZ$dJ8!AZs6%~Rh|90|WlGUqnW=isOs26dDT*zl-)3K;70- z7_b6GQlV${88ps<)Ft(+nk|hM<$9Kaiy&L|qgE?=1#m=MKyq@|xU~K)J@gac=0JXw zEN63p4Py$m6Lk;0Zdx}+)o*Lq5lyEn7=Mksz%cUtDR?->-o}|MfjB;4TDd)i0{vEo zqzRInBy0vsF=gw%Aj2wloM9F6?MuSf0!WzcXiqN$aKx{hZ?*Uoy~VKy%IGx+2UEy$ zbZWf={wZ?#)0ihYbvFHw|3e=Mm)Iqdp)o2*!!JU8U%4a5!PI;$ZyyF)GY$m{>~~C(3)4fKFCowI;VYf@$QsZfbx+ z$vw%T(w#d`1|__PlC*fFma~{0$SJ{4OB`zm7XTnCWvdTmOQq!i+hOYbTORnkQh#hR ze|+M(7M1l}q8h8sp{0GL9mh(C^kR!vWMA#zmF9u7%L@>wac-qXn{Be#WdJ;sNO5yts>^S2N~e|Q40btl9C-wh9-*JTp}&;zod=Mt64Zy`SM z8*0V_sl0#pL>qX;pUP5gy2r@Cv0gRchZl7Y4!Z?s0!H;z3#@2+$xFYT4vG&*7`?~2 zltYa#-<3Z-U9`B$|BB9mxjBT!<)S!%{sM4V{&6J6C)^pN?ah2~#CSBe%GSk%f>&ke1gee?b3Uwz+*{;$#f2sI`s&HiWUA%BT&n7k}1N63ZcHdC5)oI1#D=J z2n4J=7S7pt)LZEys@}kNaa98e*jXu&QP<~4Ci=mNeKVMgfAN~wNWhN2z6ifDd19RM&E(!zwZ7*?Rbi-g?d4}SRXE+LT-l-LHvXakSI&(IxCB_h@+ zlMB!@3PJ?%B^^;D#Xz>Ao~pV+)x*t}M09=Qa@daLik?zjYSlq3u6}>~vT@6oEdbu| z_du6Y#3<6Cxf2thxnJyZ3ZRtg-3sfE4|&as%ccqw);s-l|7u7aAc3P!ejYTzI2LEV z&-eFnbAEP*6>_4f{d(W;{O`O2VMg*TGLx%#(C*fqAok~16F%31cO2jjtIS14%JU56NeWD@@towNOn|!7Cn5HSScdcyK<9Yw-l``jUo`nNuHth7 z;}#Jv+T($16#;wbAE);bwB}E!!QZ{lcN>^L|7TV6x?n6C%+e+CF~E_&A%1W-DruMo zvqs7COKPtR5-C!|k_RfK5Z7*N2#OY6)pqM1tCc<~oNkZP$W*F$FkECp>vhUp*9t(_ z;)H*(#D6y)Kdz6zwy1iiC`Bsk@l?VNOsj8(H307GM*b1PcJ6_1A97U&p z<}i*1kN@t~C_qco_L{H~fAfe}ztx&c-ue8|kDzB~CZWLnaQ3qqR8?!(8H*hcit!Xd z)pv5NPSF#iR0IZ>qIe()i%pH%FE?Ai6^+L;X$;&sCZ6tBY0v?y3laGrSbO$AdY^M4 zVtTQWG(Y%U>*o@Pwg3QXlZIGn2OTX}e^6K>g&-XyQ}$^&A#U)UDOL%9mHGnt_ebL9 zyM2B4F_3TWAvpaC!g5)&X}>F}KVdY0q5?qZhMqnxR&|ijrt`HBRGRzpjci<^SNgTq zY_v*r+{se&vsIQ-mb#iV|Il^zUQucHP|%DCO8{14$W>k>CCY7&EW7Ar8iuSf^SVs0 zaDSY1l;x;MK+pEtAELOwb5DQ0hJU{;{mBshiAOuSl@bF*?14?USuDS?G~O=3_`e$;abMexw)8VX$(KkFGk>y6I;dvTEob)K%ESq`CI1p>8zv)9TGfO)t>9fs5V_>uU^^&|uqpQ=#=|!9? zNO90)Emp_hhe1PfBlEbco7&>2ptea@naPDFYN_?>HA)6u>Nro{+)&W z!MU2aB70ODBCFhVOC}$$mz+SIK6)`x_`b{Kc5z>5tN;6N6YVTE>M8F;xtid z{r&|za5qJtA)oyMTC1S`5HEV>A7CQymj2LxD78-@s{D(4-T&qo>tFJ6e?7q8ppvA8 z`+MtS8q;g#ls@r|8&HTg425XFb9(y<=;Ar(ZroeU2#MoY%CW=#6_M@4JmYSBc zZMEPvQPl26?s`L>d}5g3K(?X?a)tjO*)$lD4DP?yw?S*q-_uur2(SLyfBog2`{yy~ z|HJV*c6qC6l~L?B6o(2X{~o>ptrYHMHEVt==y>`R+*ts0uJ77y4{`VsBd(%HW>yb#i1aF>|2oYPj6&s-=DX2sR~9O z?r4K1eU+f8qc~`tMiAZI(!V(Eg%a**3WS>Sfx@zI9#t*oVB7g$UMR~!&FgRldoGntmZf4Wl5XJA_3}HYxMro(C-G^+03h;R%)fI*2?=DjSG-X#PfA$;jNs zj||wY?sTK0GD}}6_eWIM>q`0~4(qAk=+|c@_j{@SVxK)*y9KYdo*-T&X{axtc8Pe) zIvK*A?NRGWRl73!hKy|S120Pkos6`q99sb39?I;|IP*NFZ%b}iAodDp!q%87 zyc)0&#F^(}H#OKrQKQum4zdxXOeQh)D)K>%d(B9Z)LG=J^yW9pVfP&Ab_@m(QWYqb2&GQZ@4<>6MO{QW zr5bC#Wnf`ZQPHj_DSoswytT^i5Qen*lK#l-CZqOS7az^o9i%VShe6oF!gba!gXNd3 z)^4OLCO+HD7^H5$4-~`~m4>xUpwxN*I-b2>`>40Q)6 zHqbS8?$$rP_6JT6eX715UV}b))(OgRBpkiRrdDjIF>2k5)0g2aTwYVQ z)(4? zJ-L7pDOpy_U~a8q=4IxDk!t%xL-RdhF_r@rF6IF*W&f}Xd1e&1Ak(%I|Lis*=&@s| zeTBwi=?3vEBR;8mD~r-ExA$Cob6HWHt4DfO;sYnA#D>84Yn!{q1m*f4u5#OL2SApX zWa)I@I=0mWkSOTJ*4jv1^n-__#92~c(zVcRhz_aBs5;$nZ~aC}QO=E1 zmrkW4iwJX3tcvbK<=W6{Em2-*%GNh|-q5>_MR-Zp0PfE22A$1;={29Pm7pz*c(F0RP;`Z@OHpr>pEBW5VZ zIynFpFbIeckbefSy?Pz-Q3mMHW> z-tjjL7`wZh+9-C0BPsW`X@=~kpMrJNs9kIsZgNJ7G$<=5*4p7l0w|l(6 za`k5tWJ{q!qT?;Ke3R@=@~_@XIS;hsSI20m-KSESdN#^clQoAF)~##PXh2Bu2B__B zmqFvkx9V^AeU)7RMqscpL5@f5;>y(#rgM|AaqMdzKr&`2ZS=c?iu3Q)=dEhA>QF%~ zLLTJKuBt+MHs&EJ1zBSn3hCM16_3r0)ia%=sg&G@g#^J0160B`TEF7$@M7S{L8`9_ z`(#o|06cUpwD7v9$tQC{{qzr;%QPwuPUH$D+aD5wtWOV%41yr513QV9Rx8?%cq2Qkh~RKxit{0ECdFMqNgkX4I${Leer@$&-;LX9HVj%sELvk?QZp@-S6F}se;%lb z5c?30JiIBAxd*FSq1&^rQ{Y%G6BuBUm!!ya&4!3kh%8+1r4=;U!iXw$Du>=?FfxN- zM^lrIJw8Gw{nsa7h=G&<=j=phqr2It)>Ew`rFYZ=k0Aj@p=kmv6tO&UFovk_m65r- zbqOHHe8dQFQI0cK!*=^1;O&0RE~5JEPRj2XfpAQRrl;^U$c*B-u8QE~PP|{=5x2Nqv!7)M?q{zth9w;VlmEO7t(&9s7~fep9LVz8zPy=qP&x~E=kZ7Wi#|e7(}z^_k*be%*E0C zB(xg30Ek1mJbqMdxwcl{ctZiK{K(Z2=G>c6nc&m&@7(cqEgX;Y)-@TN09x?wKDxlL z@Zz3bDrEQaH@|YB?|Rf8n&JZ2QVwe5z*oFN45-bZ%{dCa`6^MpJJ}HtwSo+LI}djA zm$v69rb8pSfGgRmeJl3p2WPT+r3`bvKeAxq$bsZapRA#A!BsbI_m&u!m!~k`UN^{h z?>z@5A7rq{Xticx$q~=#01CkAKn~Ac9ozZ`O%lpv^OkHb-SUvvrE5~Psl{q~S$Zb9 z$@|jKrt7x;P?=K}-{8ij@?@zqL*=HWwy-Z=pL0Sek6Ot{9Jod6bi~u?HpskUG*t<0 ztV}!HM)`J-6Q#r2emzjRUN}Y*J_-16a~_ko!v~;}2vF)tfKrcIeZB6dKNBzl$Kyp} zGDXvGpw|r$0owpkFY(Z#4#eSrIGy*i>6{vJ3Fk8jN2 z(lb8~vdS1}2VAvw(k;(lN~u5=N!}c)k$3KdzX611Ikia5$gX?uTHhAHML|plcQAWN zT)Q(HW6?SdAa&9)^7jfeY1zQa0ov7Wg&OE*oujj~A9;H}@AXBCE`ejq-05(n%fo7R zKS4VgXILzLL^~Z`-%{8n7c}F6KTxi**K)~t@aBQY&g3FQ6#}n>Bv+gW(@m2#fgJmi zw@b>shmGnp=Rn}_0T<*p1Uclc!vNc9g3?86-XKtQ-uQX8fmkKfB68l}@WhcQ4r(~L zB6gfu$CBbEd(-y6^#Wjv*3netQLg3;3;LZ;xg?EnrWGm4(bV8ksT7Nm{RoJ|?K;e9 z54BbCzWSuAHmL!uDfPPE!p0{SYk9j&oFa;?0rDzMQ5-S%j0QN`@j!HW0XTjLM?;l6 zRPyn6lF6$MaqBL%<3^(nvZphr(f2;@Gz#(!b0-~yb4ew=!>JeZ0o{)vPYQwOd?Vb# zLte=MIq!V~yvcXk^Q)?^UaO$XQNUEQvTR+yr+-sNuyBAWl*+$)@25gAZA!JpP{0Iy zlgS`#)>|LMzPa}x$KUE79$I5(;XkMS!^EveUyoldakBICPZ?Bhe>Oh{V9ohrJhj^z z7Un#c5K<_2BI^DvK{7n*7#WHyA+V|o4WsKXFSkT6J}&#_QfS?8Ull2d+K(u?k%KtK z%5`uOuYjxf+XWq?r_$Qj;O{JA+{dAS`Rf<8csD5%MASkkFnxRp`lD}VF`Qk zS?`@(uZUAH01>DGd_}Ma&7Xwze`NeT9TE$vzQo&m|3t)-3J@<|%#3N_& zGoWapT7W|3&-{6+ydpJrb^HpPa#R|*l;$0i2oQnX`qv|nUlB29)=_h7*7Mg1XNJ-$ zQ<`U?{P!dZCRnvId63)cgg884O8z~Xl5+T@XR32EGF!tzqO@a2Vr*D7d7h3 zQmt|`i%{|q>CzDqMq&ZAzZ^1m8D4;O$>}tW2Ew2Q0&^$DeN2^G01S_JM0>$opD|_C zK`hNA>0oO%A*zzZm^~frK}lD_*N@~_42bCueupULq9X%m4C%#4sI)ER8M z1rE8wkvC7u3 z-smYkd;8+yPm*rNg{q zJGNWpGOD0Qn_wqeu3dF&i~n%o^Y*>15pqf@YoodnJ^wrlF2Il{SF^Vw>m^KV;?LgOw2U{2#oid z!9hV<>m7n<2md(~JVvnFc?zy|iQJ_a*Ew}qOKHM+in25Y;Afx9;ja&Fne!B}+}@r( zh%_yEL%JtbmIKj^qj|v{$d~pS&+Pdu4i}4(rMQUfwVY8of$R_GFAf68^eK}F&fA?q zGIZG(#F5*rM2)y7QboMR57r3h6P?={-VrS-0w!YdnLb9PYp!^seC$@cWvk8$=RqTi zZm=6+CvQZuh}tgo3mBP&c7*W?8w^%%72?fbv;^nM+`IDGb#ZU7b9F^lEeDH`+7ojv z29Jafet0;)ftb@#9PeIUzjm-No_1pl4el$j_V4;$^0RS~SwjB+={))5ZlBJBZL%K7I^8T+@auor(H-C1z-b?4BjIV2flx{_m z1b68r37J|kU97oF+slF zyBJNThc3NAQK~S&(d0l=b#~}cgHZu`gd%w4X+?IrX2-J}>BbFGz1vi*j$bj;u+xMG z$lfn!n=>5MN$wwnYaQqDt9w?>hfBV0YZ4O(hSTy?jl$c(6_TKq}n%AtJsrTYUjeAoQ@{`UgzPL<}5to$@ zptOL;i#?@1H2S8M5mX`-)YKp&8$ivEA*7d_JR0nYH{Wrihh~Y`aEPVHx)R7NG$Nbo z%Ptuv@rgN@pxcY6UiIr@4)8eQa`PoTYMO-0L$|;mQhGbmz^kSwPJ)wXf+$>MxE z)g=A&4~Dm%K;Jjra@i$aJ^u0WRf_!K1($+;^2n0>Nocx1+3x`3c*darqw%3$<2Ihn zIT#+-TUENdCUpr`=!Lx(>BWQ0ia`743fFn-XQQ{@=vY?VGTeSAwM{3!J82)|b0O9Snx}-WiHpSx`-ZVik>XKvv#ta3D3)aKDPD6( z2m+6KrmYNolb`@TA3S=)1`g2nN^hF`xdb;`&d*e@XlOdAe*e}NvGIJpe|p|zG?##d zarLK@A4wnZP_j+VuNhPxaM+koomik89@%nbo@nE%`U{GU_Sy7uD`dheTchP0>}J!q z)r;+gpWQa5e0klJc3~3~6yIM-eL0m2=z^XA>VNCnA4l8;ZAMc~L69PUs}*$9vg$1c zw?OGlZ2ton{}Fock75q35Mo;g6 zqYp&HgmJaLIl7|2PgIhX1y~{`gh@t+n8N_8d6= zKuC{$v+K-vZ{U#(J=DXk`g)V{9>9Wznn7EMlV$kh7yZ!`|L=tTTOQ{BPS`)X@c*B# zu)e47BFuS>Kc)u{%`TTJr&Y$VUmOxN92ZhYPDu@y=yK_|z4T}aW01{O=S*4}DtLay zg#)B|3@(Gt2q(M1zq0iHVuKZpzx&^`W&R5WO?nj%9AOaB-6c$X`p!=$Kd*4WLy`#1 zM+&DfY!EDoxQ()UF@dC`V#^~%7nf?SXD$SiaD~iv=)}GRXSKfQ&?$SJ7sqK%y0Fty z7{+3m^KMPm6g282k^Ikey;teag&1~fy`gDDCx@nW^uP^Sy6XKS=cL$iNq^XBy70;x zS`<>GBP+pvyr{j?imzvQOUpZXRC~`ZnSm>+a=+9MT zdxET&j-1P^5(*VV_FaAD6`HN-u|7l$N6x?BZipzHARQsHQ zpN?X(ac*&~v$J)pU=QO_W>~D#N_6V`F~qy!!8jm(U#HA5L>BE79~6IE*e57n>UNX+ zu>7xWtRGL0x`E56@BT)j&B1oc65k-K^A=`Y|n?uGG+i>)2*rhr=l7DEi1kI(N^ zio0~f4Lj}+c9_ql*^$i$3yY^Ktx+r0jLImbDy@l_S`3whYA^8mz93?fIMi{X?G`wQ zVbXBulFr3W{ZfCSdy!@5!Vo3Yttx=xKl3I7YC(?DYl<776CN(bC@;L}p=K zi^|ywLGcUS^e=hIFqxtXTsk9fNDtiGL{%Qf?Pj`y5Z4*<@qf9D?kFpRwn;==sL|*8YiAS=sM#*RMYS@j9!N8_$Y%RdWMgAHRGdETg z%O1UC?{I4f-6g}3q1<1qIYymr1?}Mc+JSr{9kJWa(VxCpKH_@~=V|iyuStgEEUD0R zmQ<>mi3DPef#ZY?`%!Uyhy%&^_7rB2?xQ6gOHU&8GUG*{Gn@$K5S}i=+b)-$6HxbW z)FR)>I=gjWW)ZufmUO3KiM{IX$ji~mw3RuY1Dav?O+X`gg;%XROMVP@z>Xi`a^hNF#RRJ(mSHiUvUsMAAAPgiSZ zi6*8fxi17Aq++MA5qD&T7>?ADl_X(s>B&4`0hj(UStp`fe6dCqeC{G4gK(#cDQWix zx`6<*E1YpVg>co<0@Q$_8qrm+YmjzPJEznchgm9?89lwEEeBeLgrLAj*`bte@HUUboXYo96=^(?id3vFSLn-P!ZigcI3 zvOmPnlK(Jn*=TJySEHaT9CTg)%`1B)v9Xq%*gBT@{g!c0PqM)n0aMDlqC?eso!;Wk zsJY4Xko}HSV7hVs`uW8(8;U-=dtU{dE#4bKPYf)wcI{U3(CzQ_GFfy^9Qd#p9a5tE zmxG+PMP_)@?|QH<@pSCz*gPbz{uM?I8622+&rVq99)Zzf$b>F8j>|-+s--N)#%1ZE ziODo?=^cv%RpLW&Fb+6G)Si18p0+o60hNVO&!-++?CjZT1EqrKT)nN7G zyaSttuWJ$~x-zQ0nHz1MS}TVsOTL4l)kJDJ2=i^x>m++M;^B-kT+x)HQGsRgGY>qf z*YwJ;41{^zocgNhFlxwe$@_>O=HF=kk$gErBK3+#in6;$*YN8CeZoL3bTz3{i588{ zdFKR^-sfAk$iBPL_edp(nROJv)Hia@-y7;RI9D0Zk4__t>}n(<^5SP!;T;3yF;b_* zz1E!bx_fO*py~QA`qD81r-i@nm7=vDqQ|aMaK+)xe^o?q+f806j^2(Zb*kXc*qgGg zwrg*!0mF<*l5fH+Gg6@rM#3JX^aSmE35Yv;PAU3igrtoWY6!}0`zx2lu)+9p?+V;c zJ_Fej@r0|8rYrs)Iu=&?t)I(t&3WO`Rzc=X79;1x;e0^=fEOIMKotWCi=%yO)M zcl*e|%y_MzRfWjB)%4JPAwcj!EuyA)$rLQ|O2+}sP5U^^I@D?@e*iy>ZqYLGAiMTa z!_@Y^Ia7w~Hgc(_V=oxN(R6_utEYC+yN0u!f@c@mxI;QE43h9<1o>bQO%4v&luQoT zlsb-PBACQ-2P)|DY=5nNhhv(QvUO!wZn69cpT(-$;8iT}pB=K#=|j6ECBkmPoZrsg z%oFPAAPL&UP6*rXell)};N~ani0qep{VUeD4q#b^gr=greCnfFk8RFJB0#f?~iCx^WUxQVaf;-O? zRr;%>x?rh3zIA)!K-u@A0Q%Hmd!ikteSR=q1n&xqT3qxjOQg|xA2=!0r))N@W5{yL zcG&i|0KQI4PjSYhan>BP`>f@G*V(rLouZUr)nqxF5~?+o*r0%BoQZ(Vyw_saTYmep z@w4blUN;rz#eoPaX>Md6IcN%@3?|GU$1FvDaTanqXR?VeZfC6zic&&`f|(ZhMi>@< z|Hucksf(Xpbw;;L&y2FE$ug*nBWQ zQf!)ufJEdvIdb>5Sbcp-1{jgsTk4l7*V<6eo7S*-eA;GCFYEypiNqD<0Oz^q=8pV8GSQp6O@?;8 zpC+8h0R{pGs6g+LeIzjc8u&g7JQG?tMdQ1Mj?0`>ov>$^d5G0YlgzCz4TtY5`SxnY z+U?S{b6zc}ckDqOxLi>#Ebx11e)pGdeEFl@#b&1}I1IZ*q;Dhpy5xlPeigLq(3TcR zn~-ZncqQ^Pj!F_15WH*>{wKIb@y7eJznGZRLScv^t*n<~3(73HjyM8R} z8CsWLy^wH|+?_!W&@K#ub`2SogFVyjYnM7(5I05SBF$re4GMzu7*=^T^&u3G2jM^s z)QzC8OZ%GfI_Nbawa*A!nhLAsV7uw|e%=5~M$crLHII4qxvGt4!F^4=%iUYUiWOml zv~Nk;UN6>Ef z?xKN)<+Tb$Xroh0T$wGCbNbQ*tW^PFU9!B#MKL69 znG-!L67SyrxO%O#OC2}=cxfHOkbX1oqdB+UbQ+r?2fNRe36@f7@KofKrx>_ygd_ENE(x3gPL-}W{rhr zsZxFLs@(1zDX^`>@=XABwaLX5PCdh&U-H`3^jxy6CQ5v|6@3oaf5VfFkw&L62MxJ6 z@{y~690K;XEa#(X>Bf`n#;D35_rWKB*N?#9=id^-8v`+gXqIuB<_Pl?Ckt;eO8K6OzFX71Fsf3^e3SywG0H97|7kSlOUsodHa#sV)L$)Gee#G#9M}F^x`^6J>Z8ScV7)KWqUrWX5ZFIj-6ficu+y+$u~^i)d%n z2C&cIxdZ*m9mK6jkk5$Qqcc;J>MhN&ZrI*jTppmawJXoav6tCG9)R0DsXsL%VZxyqbOeXn7+~3RK1s$^?(?rgE5?H9z zdjW!sxMqB6aW$5=h+S^aPaCyWNWr4LE*)5xgLQ6=fO-imt1Mc zOG}l%=wgewZ#DsiLtmIgQY+U7>DDsXGDeO^c>^}zqVN0=^p3KXE1k%l&}I}l3y1o5 z;Rq5A&@U=t^S15X3FI527%3~fE`r*!`N5G)rSuJO7*fJOKY4W5)*gRXR{|%8B!{?w-gZ=g%KFaofYPtRoP!gTb?ugdMC7ooTiVMt zBhCxMpU(a)cnRK-$*EWCPX`S=ka&-DOn2oQ74Y#n6{lDg6~*GT*iUdK*Pa?i6?K=yYWs zu7yausFZt>64PgqG0K-r2J`nVR>~3RYrE-Uh3Llc5p`RGcj}*1T^f;PVL~cEF5wk7 zW}wlP{qyY=KSM30W(y0w(1+pU5Afj**vxTExYfN^tI`+S#@rij>@QEtBQ)e{hlQq@ zxG$9DkaYTofcr0=s>2Uyb%wG~#3D>ql7g>hQ=Wt1qIyMERzF>u?H>ZpE)p!uBABV2 zWTAQ$)7b%<7JA2Y4j~M|ceg_Bi*62et~vc|b3*uZ+*nctyI92|@tnh;n&Bb^2rsEl z$y7+Qw$mJ319%DN+)Kj3DOwQ$TN@eY-PGC{1&e_RIr6lU-U)<#BYUY=Q&e_*pb<8B zmw!Nfq6DOhFUGi(E^&5qi7RqjDd}@eAFCdiCF&Z+DVc)!GH!wzB1Hhf+Yq zA*i^_oT)QsFt~+e5IKvB`ZyYF+?(JA@j|tlg=hMkR6p1;0Y^LO?PfdcQ*^MK@Wkh% znGTwVDWfOQOKTN&#P}Gyj*B!CQDY8BBQXpt9zxMX61H@zuCmSNcTV-0i!%F}A6rB&?O=*-*r` z+d2>vH-5|N=|(m}N3gb%SHGOOda(lZkh41l7k~w!IA+MlnB@v`SKMCosKFyv>^A^u z!kKiqa|hs^9Z1iJ&g635FB`N{=9U?vxM3NS0UzAA04GjXGVvt?tVJ1!vZ7$r304n# zyL3WX>1ghXjy`Xq%VJOEeSthQjv0MRhPy(g!5PrF+yL%ZTzi=>F)af!-0`dOf&G2T z#n{Fvl^Ztpq(f!GBGQ1oy~y?UaN_Dgt>{`=IDkcJ$R;_OaM;8`4=1)AN6+?|i_TaR z*=q5eEOk%8+vc~)_c!#OEH&={Bg@aZJ8Q4i3L?3(N6UzJ+cuMqqhb?7As6&6q7B}! zy~Z+q_D(PyI{BlW7pH4Y(J38vd2UV6cyYxu?3SB4gZyp7 zSI+DpC)_vxArBuTrgY^E7iQ2K&2pRjXw`VhYq#SC4(WFb8 zf+%=pSvD5{iXS0aG}_CunN;nvqZphMe7}8Rg_smST&o5gjEmtrG*+>hy(uv?+%{ed zP7H<>elGa~(y{zc;UCbMgEyrq2oTaFX%a!t@JP;sf9)l!skT@hV&`BA14Kw9lu3=j z^SVs=7%02DM7=+YGNf02aTy|OE(Qb9#Zll@H6Hc#q7Rf1*+bbp?m7@7>}pgkDRPYq zU_SJOt*`vOIZVh2Xe!a`2x^e4E z&39Gq&S#TLw_%giP|OEZ0VxI@p4I*e4Y?Iep=7$(`4W8RG%IZVC>Fk6)2gwJ8s_`T zQc-9%c6x2?gBRAO6xzY)V0+BASLXU$3W5SRfXikZgA_flC*?3^$L{#fKkT|q>T@@p zdr@~4Q#%rijC;F2$$Qd^o@RM-an$%UKzM1MCUb+PNM~O>0vCW6n+iaWQ}w@s=3(b# z6+Q7XJRbi7c$m{^8Gwhmb1MKeEqK=3cU8pX%`akj)Y$KhP4K8W?q8%i7vlZ-8Th;B zQ;{{M=S??0pHZd~Is3EU7mafv^6#)R!8~H%*O!8RCQpf#zzm(f_QDe6k$+}Mzd*%$ zPU7-}kZ%Bn_I*MjJ-nAUYQQg?sd~fkyy@yyc~>yw7aZ>@p9{HrCvg|d<>jx>GXL;F z?@O=Z=|aJ^YR-g=>f1*3y;+O_(@0(98>^k)B!Pz#pI>Y}*Prno(-YLnaFzbK&c#m- zTS(8fOjkMh+`YIpCN}|N^$#W`ZLbA&D1ajD@a$R?bYl)std>}A-G|XOhz@ypji*s( zyxVy=gO@5?jqTU~eCuJ1dY-+eZO){cQet>72C`OW*E39c&N0c|+az&Y35 znZ;!IA0=IMBHl)&_tIo%2$je53Fi)T0+}T2KU8(n(e7IPCnMt+M&!X}*wM2_Ku2#F zWH!*)SqVcS2^R}>aFJHN7ELeXdr~TyQ!fITVDdkd@j-1`dCBYD5- zjF8^??%v0wO>RIK7|@;j4>kQ(to=h)arT?t-}x*Fiqo$aHi$s~qA3JHa1Y`LJ-hm! z$v?bfVVT=$z0#d0@|_8}>Vzke*{K1@x?s2*pA?(`I4=8Vzd?`xE{E^~Px}8p?owOz zW`e~=qz?Z(%;7P8_iBcKr3YRVpS!@?4L4Z`usaX-w*N%H?r#?#QqV&&O}5t*O(BHn z)Oq8*WzrKDxM)1o7FGI^2wnE7WciZ}XdU>5HRXk3Rz&*^my(;qQ%TssA6)`R^Zaie zlG2HTml3%SV!mp5R&ZqKRu1@m(k!?3Y6yst01T9DQ*W}YD1t@v-Y3}@PV6n08MT&3 zF4e@2{@t^{iHZJiUFrVs8sJ>Lil-XMByZEFM6jksKOr7CzT4%4`e=NtKoM`lLqW=>V_5G(}4Szp4asn|z zYzFOV4B>!|d!Y|ul)}%ObQ|UFBUV`MzX+o@8cn}zyIed-`(=ACQm3~s7jb`CT{&YU z$sB*#f13;}rPKeRAm!ieETLOTqlFHXTh0lB5H~4yabC`J;P5RWb*b5iB+C}Lh^RkN zGAfsk;DcG~0QqK*sb_{`zR>1=Yqij}IMfL-3DlSTNg2k!0>J!O<*^PbJO1m182=tF z)Af^w(Yf83Gl%X`G^7!~@j};dF(kK~u%0(fuWdw`QO<-js?N~m2#DBO zWXWO?vkYDck&etwaPSFC$W(6WR^;dL`jyvl?wsA~9=?8awBIc5(2oA)4J<0p^X!w|_|7hF9KYmP4H#v=-Rex5m?oASCGLtl9*Q+SM)!vc<0nF(&f87&G`x02ryu7T;0a8Jg+` zI!K#wZkivH^XUPsS>jKR%&STsGaR};2?k=$7%GCN@5Y1-klfur75nY8#4QYIE(n#g z=_NXt2)-4g8tK@BnT((IpBaC7sC{}8(zbH>%KXn}zh0@Apfa7Vreeg-*}5aK0uUA3 zxWh~4g8M$;eaS%!4P+mc`>q=nwhsSq(wSK6F`GgW&-o1WKYI>-)f_8iuh#$zLQ_h4 z2YNrxu+>ozXT=fP5GHb2)WWM>j?^@7+1P_ne$EJ9?OZ2H!cIrsCP0G0hG&)8AGcS% zoT@r!GR<_CWzZzVh#m+bNz1W2^Go&qfc@EiH$wRaIcWGV@KCCJF)~_BGLXppTt={G zb9rsg?Mn$#KYg*?u0Q|O$ikkW!x{$1f%TJz@If*jNN?^~f8U8^Jf5=!QASBZ`WbHX z!ya2o5SMe?edS^?va{dKlWGe!Rzgmt&?vVYG*RShV1br|WM%EQ_;%S!f=kZZ$XYnJ zETqkW*&Q~<3W1NYMn@-p>jf|r2#rB)`KGCQ-Xih#rw1!@4{~tER5MME#$d2ncykmN z?sEkp`trMUrvRio?Y&2=Ob6yM&@@*o(3q&db^YKBfB-6Y{t~#h7ONWg5*>Pn@w}PZ zE z%tr*DXpc{~#T<(+G@`x<2t3US2dwIfIYDSN@*pXiJQ;xt@2LqDhvYcJO!gG1A*>42 z!QR54GW&YkE>hqTR)`zJ1bKv?4Qk{b42~1aLjkUE*|icStVHXgy*!qMfNjTPv)do; z3{O2KAAdztTVLSR1aLpQMz?{D5`uvZz|n|}cE`WaYq|75eTMj4c3`f3c7mTEi#(79 z7!eFo)eNH{dGSE8l?atQHUD8o8ZwJdv~l!f;p|5kp6wL=zGGctUSqvUS`27{ik4Po z?mflk(`a&W@W8Fs-36SxHCJ5mdBYN2{SH-mm(SvO@@*Ers4e_TCot%|#NEK@9?+9= zFYZ?b2#vUuHQQ5^y|xzv$VdRfv1v=Wc~QLPxd+6=__2Mb3fi_89mq9MlA9<(Xrj!% z>A>bocleT%0p$!{#DC_|yQ=pY_P?HwQu9Zk3HsUIHLLlBZ(6sfJl`wJ&# z_Q`(wC%YIn6=*WUILT#9)*O$CL(c(sVaA<$gtG-NNF`^n?!%=G#avK<;;^JaSU~40 zfm&|s9Uv@z2_RTk=10qQ9)xi=%sVsF0Sy$b3{(pbtBSKxbizc=mD`?vzkuaTK86TL z$`*HrU_xaoRtPVoUL>8)E7S69d!*%ACD;wC?H`IYcR@AQqMzf$3P2phveuymL(Fx` z%G4uhp+KnP+2(3Rg5`iEF1ag;7q)YWoR?Q+XX`!a|3HBk8{|KHyTy-L>62!#r;YS!nT)8i7>%Q@18Z)VBDSE<*8)1 z(y9L9d~6JN>d%qHn+N(hf^lSR7~e`dKg%7*1rjh6-=oZ|J8veQ?ikfI$kb6sQ``AF!2d;TbQ!Xx4r&(U4j8%Fi0?EEWU)vMnSsU6;b8<8Sg6y3t!h_E`` zVS|mZus@s`T=*1kJ|Z-&(XZj7)ya*9^vMk%^$QPlT!2s}Hi!MUn*-TQ!Ykvzj-Y-h z>wq+|eaIN7P7Ei0K~$vu>!;in9bz}2k#kcPJ#P}Wx=d}8(w2P03{V~`l+LKin^)xM zrml(9Xcl{^KvWk{#{gs0y!v&_$9ARX3^2@tKn)Ff)MgX`*k;mjCNZgAO(EKhJ3+^v zo+xy$d8^StP;tknc=zn6(#!lR`}WJxM+6g~3wcnxpfT$T`_D@B}Lb zN22$wDI$<&2R&uyLmY^5B;=IL-+bd4s)^i)3OfDY5m7gC&9yP7d{fAGGV1yejVu7^ zXeIxKL|q4*?4Kf0&zmNTN6Jtrqs|G3ex=3wzyp4;52T;)P$pqUBS)hOaM0D6(D~X% zTw3Rg+HSqYW}bLQTfk?~p8%`{!`$oe-c>8-1f$Li4hr>VX8?ENn*Zob;LvRy@{vMw z0J4>6hUP7DBcPU7&M3svm;@Y&Pr3Hiw#2osQs{=X5B$Q=F~nfCuu{zKWCKX4b#AQg zUVSpUfTXFk4iZZ$)~&tE3%9Ah0}Rd1b?_1!aqqTO$WaMTVh1>3feJw2EaSvflgO|Ne-azN!cvMn{PvpH>?`%)i5p0#hY_6Dfq1z zj)wt{09q6PKI<(Yp?c*o?K6Qm%_OaqX3!E-0B!9+N&=3}250Ct9e~y9QcSyr_0cGe z2%gA7^Um6}CIM%ges;R`O;aLi-z(~iR44EXu$(O1cJTWH$> zVWr+jsIDq-a#i4aJ79xt8KwD+Ewp;?W4kQ`XwvOcZ7lhB&N9y-2&`;xd8%rqGCQp! z$o%MVyrXp8?)>O)?8475{Nr@w{s!W_qNwD<&hf*(MKAaBJJz}#X10M_kNFYy3!BE! zjdx1EK;SLYftyOX7T6}v;%@tg@9sJ$4rZO-Yt$Vt=JA`5vl)mz!*20GFH<4oCjX(x z7l&1cm66S?jmCf{tC^QqdTEyJSTxIivEO^J1z<357bGT{PjcBH=t3)iCJjeN{HZ4e zpVZ$|-<{BT%zeRS0(V>~R9yp(-#iw(2dGHkvE8N9)ZnrC;V!ptweyB$Ni)4b9j?6H zehfCsM?hZ(`#!gh=4OiBBZpEbAjp19Q<2owt`5K>&_W_v0E-Ty4@&U3E94u0v(d=a ziMzQhex1ByL~XC*yg7`>K7i5v?nTNR*swJ@wZN)n4&fli&e?c)y!9*_1QZB(O{YWA z9SoeA*XHyg$FTFeFBxh3MN+&Y{>VMqe8bxvC|yy9v{2MIxf;V6)}eVj7vKZ9rk{c? zsKXzaPCNs2J?Pdmy~}MgyaADbvy|wK$NTGpyH!uiHYtmgyXCjcKn)9Yn?t7>iSOmwz6?P6boZR;DCJ_JH3 z2K@`s!(ZrsW2AV4C=(kILAsFHYQkxmWK0J5yYT_K=yPJWf|TRpolL&L>83F220)wp z98OresJNhr-%e0+eVh+vi%+-4)$&2T&#ZXCly^)p;nco+Hz0=A*9kqm!bVZLJusn-(m%v*D9=E~ zwxJe4ceX}=Fy?MG`>*XkZ^|JgQ`q?8my5_O90Fc%F?)jCd^YtSma>)sGxY?L^L99;DK{Z%|ZG{Hex80_q9V-E)K$R2m{^_r564 zQafb7?gxJNgWJXv%Z_&D$C&m}Mxss*aklWJZNg9Ic0=zdxQ&DJPT+!auNkBO9>pzY z&2?P&irn&33f`KN5f3I$BX+h+vDPQ3y*+O%oi}Rg7r|d4AjFZS8Z@0lBhYY(I`m5= z1BBpU9&|;8Zhr2YoW${)ui?&y2hX7}nGd{Ymq+os^HmSth+AaHWVenkIG6s0KouF< zKorO^1%-6G^-7~pPUsp}QrylS3QJvI(t53It4RCC@F#r2Q42EECt+|9b>C6*AFrnT z0jx*V<$KD$N`^Z5mb}$PU!|d#RATlDd!p5W?*KSUvl$zls8-uUCjDh2=Y2}yOo9U` zUt3_r4NJ@OA+`1LzE#)7{||d_9Ts)h?tNb-q39@r(gI3~C@HOUceivS-7}&fB_LAL zN_WFZ4$?hz!zkU|HSZerx}SURec$`p`+ed)?(2B};+TW^&HQGq^;_$V&-p#Qg?AQf z1AdX$3B%AI{XbX%B*hcI5&(4=PfRpRT zyuYaD5zt#+`#ZNWL=^|UW}>^Y&1_{lc>X7QsE46qde)j*;{-daQ;I5CN)_Ds zE5MX+BynsF9JRxzqNuE(;j^lF89csrpwyDJwtFynBd85}f=^{y?#_{XvJc2=-owW$ z{cGGvQhZX6Z7+8z|9E?3_^rG-&;e(n5J7$%oEU#1@m0v6oY|xDI@=dFxc@pDLq2hy zj}rVGd(-Smkv;Izt_qCT^~95a3X1-8p_4a;a<#AulWW;w1wJbn*bZnVEq2~Chd(rH znHfUJN@Y75z8p?l*ccPP6xIET?=d0Ph~R9UJFI3abo>l3^~wv06>GG_1_AV2Usc+a zd~^%E^Z*hh0mNq#i_NbD>+&Rxll7mLpQdHH1kc~f>vimV&J8+sJMz{K4dJy}Iy z9sk^iOFe12%6v{;C&s1}gRJQL*5<`16*(OcO-kS(k8`XtNaRzkB`>2}I_JIum~@-x zx_{3;ML3XzacByrGLbaTI0KcV5Zkeb$!UO{yn3_N0(D~r&jx`V!go|FKflUWZ0F}c zgaQ9-)K3sE_F+NOc8tb4Z#_BdEkA(X@iZrhwXLssnd5=&bB`7)9e*1KSg==PuegnB zZh7+B{0)5?`v>S#Ct+w>5e@bOsf$pz7YMz1@hE}Iu04NaHmH8P4ZY^g-y{O+fQC`o z3>4j)Wkr6{s_!V55^N59mJu2CuqGM*Mes2X;{R=Z4VxElS2;)I3m zfwEYl;?otS3BUgm-c-|H1~xi^TkPgpMKsZ^1&}y zcUr-hvhdZGJ@M0JLkoF04G3#;_l5yPB!%A#t2dGFgifUWj`H6_H2l9I8ifT5 z&rAQh+C9HV#!Nl=Z<2#8-Ss7UoywK# z>y+ELKCP`9SzEgsC zA8|k7T|GdhA$uyYu)}TyEFu7vmiWctCWMOYb}tN2X?#KpoA0^5 zqqr~{U~9YA6Fh*d*9ZS|M$npzi2DE(h5y?xx~TV}j^y_yxA~4+^=~B~;_bf~6N#gY z8zpE%Y>*M+iTtZVQv9@FWL7W#W09@@E^qRGU-#nY8Rh@(;s2=lZhQO7ykv1Z^_*5X zjt8y9O7H#+1&A#lT~#Pn4G;=~d!2%dA94 zON@KTDXg)~pCz&Xuj}dkPtIi1Vy_52nIs{6#3A>Otqk!Psvj#L5s6=` zTA=BjxH!ZgcE@e5oq(9thN>$8@$APZwk)OIqic8Z%lp%1gwAx`qCnG^$j!6CQ=s?I zW%jSC>+_%QZ!{fZZi|}=%lorIIH5HiDL4DA*>gTJ@#gCsu;LN3#9BSwuE?m8_qFG| za+s^WhmS|T{i6PWnIHAm=CRVp?sz__jcU$!LwRUl``K2>4Lm5*zd9}bKjCITR=c1! zQ3f9oFAE>e7uDhBi}(N5dXu*2jjvSJi%HFaBAuMN+NpwCk#YD&y6l>k(iu1VrK7*1 z64HN8Pq%F=j3uqQu1~m0Mz3>AhI2bnUHz?5CjCH|oCo@b+Xd#Wm@55ZMiejEvY>`T zVPS_Ek)EZ8{4!RStq2zze=v4;jT1b3*#Gj+UfbKce4Q$@fy|p`)2Yl^Hj~`DW*Ik> z%Pb;ix4v)D{nFaH{o9||x)i^PeR{M&!*N`rbp|##@jIHPnXV5nb={60f^rQdaT_d* zDk>ZWjox3KBq>HfYbpm)+jP9E%}WSNtwy)&4wm{eGLksYjlAwFRQhyIaoY9W^*-Ad z{dV!nVjC@mT*MC&h(D+IEo#xes5~wF;NIk>Nk^?U%>Whw=+0^hbI;MWg-a=E(lH;8 zcip^;jk-x&3ol$O`t1V0pOd??KF)c0|9qc^Nu&HD^vsFztkTV+Ub}o`u{Z$~bh2PV%$Oj{Ump^Jufq23gb4KWB78wH{YNzkgL(}V@M+#FU&{25wlp! zppq+IVj}bB>_i<1JikWhnPm2!6SXQwHU^i9INFL^<+AsCzqb}2qg?A*@!{0sO8GM~ z&ni&j`i9ywN%~J;yzQo$J?zu9T6CCb$PwG?9{@SZMCTwCk9UW$iZvVvd%og?|G7^; zU$=_q^9UJpb`R_W&@hl;Y78i7R}=H^bZkKFTt?YhSWdoz1BMi&rHhttYVk#<+iH+G zuc@yo1AX#P^!J$Xf%Q0rBI1TUC`d0cQk}n5>rTE>1#_-JsFQB~sluegBOu@*N1A>E zJqSOj}i+W9z5F~ zj@joJ<(QS#P_vU>0Ss!QPYHxvZWO)RFd_c>h#$5~AH&3nS9#{`WA`)79rHABKZzHk zh%x@R^b~q6WRK1Ds1rkhm;&jY#o+M`(+yodw6)3mRBBVXqLya+md}+p726(tfqe&g z%zlo7 zI^=~(Z4EOjze~&;ig*U?zQ2DOOnXDzby$FQXFCTFD4hc53r)Lo1s&C-OodTr$>Zb% z#8+$8I0trM>(f^(_UH7S;2GmTA(R^|+Zjh}hU3JTFudEA`o_$ zERK?LPEJbQ(Kh2DkgS;uXR+J_F;+MllUG9NWpkG?yJ(Hk{Qj->o8fsV2RJ69ILXMKoZi$_H8{`wD1PL|=c`xR3s;`~jXc6&Z?|MI+yUQ$+-Ja`gw8!%^%Bsl;Tr5z zdejRAYBG-}t9*5Jb}7I(05L8gEOVo8ZamZs89g{k*v-;VrzH=9F7U9JV7P;IH+jz6{^f*bU}v>4#Cepk3Mx&y1U z!||$qselmy>;DO#8Lu=Eb)`3MxRlt*kf&Ig_xtH%^P~4s*H#fEjWg-^AT7VloAEe4 zMYVrQiCPX$%MOdrhvy%Sz(Mx>KDBCBnz@!5=IejX_zk=1X$^P%pzs7NqBvA6Vx3X_lq*2%h3qU^CMC^d#sRPR zjLB(HuZi($vjRrEz;Hb5(tvfhI%c?)#vIwQnr3iTmJYMt?w)N4l-i?iVAf;K9_P3D zhqv{Rc)AlH!|;V~fJb&1G^s&~8xs4~hQV1g+|QE|59qCVzqX9dEvfySVMZuOIx~eJ zH%uxmKQIUos2_06Oz(T-gETiriQ?Na-$9g zXLul~IBaVvF;}u+8twcO5m0T__;9Ynxm#ww-}7xjpmz8^1t^)G`sAP1Acu!2Pb|TM zCssAhsPfr9buSy@^GKRH{3;b%g(`Z=Q#5QN8Q*4cc75lJ+<7KV(nO#aCPW14OyqPaXc`)Co3V!VtAOcZ9h+5%5CITK>{r{Jz|>t>r)EvViQVP3oQ+2*pdOT&+bNYK~w(qI=#`22rry8!5B(9gM_$I`^Ty+`BGe?`$r zVs|H_dmiX{{X3dzhkM4y)9K&ROtUx?I&T5Tr4QP$fQ@fq_3L*bZVyWS;rl0A1-^9p zH8g^NlXyCDx^Jg@Fgc`T+QNZ-81VX6W$>w^&66Oa3jvS{rxgy1kwsZ_{nU z1U~6eDAn&=8imKg1!nf5rXNDgeQ_5h#bS4LBc~KD69{K13V)#Ldm;bgg2MCX?qXM7 zWZyCGOJ$%E$9j<}u_5!_I4athgQujebMj*l`V_jcHrpBB*%n>%^?(M|ZMetL*!JvU zp-lrJF}pJ{-8Np-9ar{}079n)zw)@O!V~5_jE#8~|s4z|s zrhIXpg7ud}eleC?a+f|=WsK)Hw;2AZX5u|K?@B=6jvJ(?K5Nm1@lu@#&g zRzak}EQaGg_<_neP6MIkE55QvvDeHpk)l3Vxwg6U+^iFw_;o9F0DOVH>s$lms9JhJ-ShJfm51+kVSuvB6l zbSY6TlRHWFW8k}}y=W;J=xMdhZ7MgYXYk5qgCGdW|uVU;X`1&=fK+uOTh z=$j8u%DEpOjySiuLnQrLjZ*4uy%4>)L8MRXjhu|5JzwfNpVk7)YU+f*pC6Yuj9wgc7_gq??AyUH z7OQ`@Wo93#%CEF}dUykl9i|FKz~ga3>N&~6Hn`_-BEebpnQ!hy0woYt7>Wtif9^or zDX*@lHCG@`kkrkT(4ULS6HMJZc0oN0IoS0Poa5K8iPIg#rH=K!g#@ods#HIaLRd&-}JH!ox&wBtni#{(4N?$#u z|9<3?&1xHaeV}SF2tze!Wf8=1SvBhq(!rz*?7ElU_+5FZJ zd3YFm$dQBU5=?bF+u-{uSHMiv6iq&~uNE154YR6T;vnYRGcR>mRoShIJb5W_Ej{eZ zhTcJrHoeT}TJBB*jf=+6f-T*6tb9VMu4A#&b82he+9YN^tF=lbVcOMEDeQ%r0tAV# zcsPaLslL$S@!Y^m{yXK)Z?)61Y@!6Gj$ENrpL<^gLFlJjhL1)=D5!w$SI5akc30Wc zS~g3gy^TuOH~bu`#qS%V`XE$dYGw=xvA^dCHZC9*?C~KebpgLUWH&&mXJL-`Nc!8( z49^4=X3?|fbAoo3?>G6x!OY02!cN$gsGV;Xn{M5uhcO(1PO@iV)mTL0{-wI;p&Xjt zG%fEW9M(~+6BWmseX}jdIU35o_RxZo(a;&Ha>3cp_IUJ4)5_%tfved`2|@k>u#j)v z@VL+<5^KmS{0ng2o{cE(2}f)BAo2?tg0l||i#|(6<{ahix0+ZV$Z8#bf9r?r2+BS@ zK*7v6ro1A!9B3pX=)#cTN#K80IAZ|PK?!=K*kRooXKJFN!$^?eMl){6$7fJ@o8(pY z1jlijcSc{LcPmbHJnqz3?n$F)3dWC1mmw8>YS6gZrUCS#Wn!MTs4K7t)C_++c*&mR zP0W)HQnjE@9h0EZ{nZ5<-89i1YL{?Nw}y4^_MLsa(bG$Lrw-9B0`bA=N9_s?ylGY$ zjyVu>rqda~dwcoVtk&ve-mZyA@h^LT@Z!V?gErZD>k4$GuVqkCM>{j9CS)6TAyuet z){hsSIccyfO%P4f;ZxBLTg;dd!g0eqx3uKQ)A=nCGeR#dO=S|_iK^}BebG>U9p@vi z;Pt3{zo3Tgm7!5B`!kp9-CdEny5xKfmz^fVrN+Uac^h>-u!%6sh>mknyRr7k`p*Wz zyw1hBVg2aw!NaFtEJ8E;eC$)DEj?V}IAO(aR=STSz7i1;QQCWUMMY4y2~jGlQUrlE zTGy46Mi)#d`*Q7;H&&Kb1gLiYaLBW|lI7J4_K7|I-L*$Ajp03qG$k7Iux@$XuROI~w7~<~@VGq+kom z^QB-{gJ{CKY9~s+-&XkB`Stv_Df}Nsl^9EyjZ>cOUkbh^f_lAOpcs}>JVNfi*E`8(restr9Doxh#Bj`C_lR)>>=Jq#AB7OT zo7NqN;9HvdOw&T!Yo^Wk!Dkh}Sy&&JoN>;La`Iz4_k5>4P*RG}W{54_&!u!+IOkJP zYc&kFEK7F`2p{jB0VDY6ytYWtXwMcars^f^Y(C97g35cNK|h&lf<`#dq8hruQNw$1 zO+iiFU}xDS-KW`N$vFxVqJf6Jk?96wmlm4uyk4++-#OaZSk&q zV&8QA*G#ZYyzq}A6BLG>S4?Ck1Tl7z$RWL=uwbB_LQ>Nu*gE0ZzW}r z!?&v$Ew6GYhbBdj}e$ zuNJ|AsEX!TK<8`+*PF#n({_#L)}f6YnSz%XHjQY;v#8x}vU~s!L3QsN1;_Pf70YLj zPN=ilIM!dJmn3w^2pWAh7&X=3*LZe&{424oLUU>s)l>HQ%iib*zc+!^smtg)$FseV zBs~@{XS(mqpA)}CZOtqA{y<}S>2<#ME8utI=Yf{-_7<}}w6Z~;=4@QrD%RFBX#rS@}@Y}U&U0?ByFha`9is5T}lq^w@vU)edx4xg&^ikof<%7`U=b(+BA z@_uYuIE$nClXWHOCBjyxV$D&~r-se5$;(~x10DHxx#~}Y(M`DO@`Ve|$BF*g5Vv7< znfMx*kX!J^WR=*>_XsDg1@VMtw8KGYN3{I6H^3v+zuQ1hy;FZh$zM5PJoiGuIu%5R zAFd9>i%M^QJ2w>ijA}{hFG9#F4j+uk=aY_lb_bpLrP>9BI4-Os*k115myAFBf!E2g z=FulIL&D z&?irm09~^VY6cHLp$H;5L5n-)(9Bhtg8ryJ-mu1f2n00R=p_}3lC%<6at6ziM^IRx zdMMI>=c_qr2lfQOT;4~Sy8w{+Lf{Iz+|_w1yC*%ZB{g`n_3)M~_(pGfW4W*>QB~{P zu03cE-~cyY2A5Gp>SBj6lwJ%4P|K%KN!!6kN0|;=emT}x+W~Rr-`!AqH<;Pd%F@$3 zW%4RzUkF6u(hRu~E7rk%O5w2*AQypbT>`|Lti&j20El_vzy5GV{z$sQ+E2*8R7Ci! zV=(3RQpxxY@YW#z`@&3+c_NAy)jS>?|8kL6mt8bLx*O{zz{=%Tb&|hvnZr(YvwY!6iTb!tHNHm;BCWSI6 z)5%$D!jr$+%^c2ZxY$g5eSrdT1gYppDFUJ7JNeZy)GZ~u6Ao^4AoVb?xOX*zL1mzJ zSAS!whRwWBd93E-<`^7?SUA;SB4Ra3eWbynw5G|P1wD(VfAQw>&~2~%6wQJ?uMgZ# z7RUQ>M2`Eb8pM3=kGuqI$rE_p+F5B0d#c@(+*5j2uD1B;c{)!wO2nFJ2l)m;H;WB6 zd~xSGfCk70F6x?2)&6Ha=-J=`Z>5U|%AqEvkkezxrL@V_HfFfMb<1F&{uA7w30Lr? zvWmY^C*dP?VN_SliUwt5R|AK$42WWj@2w1`SPW*%pC0ZbR}bTTj2Cv7SlOJ$9Ai0c z`N{Y_8~ZziTW&uLRLTe;qjTFfN@WmUKA+fK9rP==8eM*Ap(|HA;dw;vRRMx(h%a~O z6*ngn%hxBMSb}vbmyb|^SHpIzDu3v#elcBHtMZ-4_%}`Ube!y z7^ksgJ{KFjyW4MWzDOGy^@m=u6`o82m)~t-3gUM+me;ys_*|ZXjQqgiO-=1sUgykB zfntA21gaVjh9cNAKUegI7V*x!BTQge#e8w7X{QN)c34V~QZt18Cl!~IF ze4szqzx@KE*Uy!)zs`9>;R7#QSh%l+Z86M#PED$@atZ9MMalXbv8augubp+XDkKY+ zx(|k8%rXQ&|NYxVP|cE$+p}(mbF?g!#U7#g1EuEI3hG)Y!pr*8q@+qrykxi>W(%F& z_L=o+1@p#B3Gyw>WnA|nkJ(;*Z;4>bDj4CK?oin66}#m54mN_m)E;-hm3^|!$ZrSr zlh6yN3E2_%^PI3kCLzEQU8myXbRae4wOKXGDl`wluhC^8d}T3wuA^D&>6M?Q)3B)q^Zwv!`PBTe z%c~M0RpG#Y{Eofc$hP1-sdsCJHek=Rd-uA|Ggw=R#RIA3Ls?K6tWX{6|V zzMxUO=Mw$Vp{TH(!Dxa(>Bh|m!iiiC@3NKiD0y3scIM@m`qF&7JmnwMkK%+$J6GG! zW#>sZ3)cpd47tyWL%SK(^5xIeh~uY27&ns>FQB>2f_L8B)>RjjHL6m6H_?e%ZsBOayqwEgIVmf()9a{&Fsb zn57lVX}PRX({C!+A)CZsvzSxR?5;{$>UgwDNU!~gkU3GV$bj!Sh5+ZiaWKJ)VUptH z$!4R@0#n%?A{y>QasLR3Mt-c4)kk{!mk1b?dv4=Zcc{|mDU`^5e<8}OCE>h}obFYgk@7AV|0zh8NhyLQKsYj+3g3^oJPTDO_oB6%CI|>6P;|2{w9#FQ&lz zU(Dq6QiF3>ET=Ir#FT*QCKDIIK&DuY;0CeEa!6=5b+7$A&B9Y2O z*cU2r_{}QF7a0SA<1L32AYg51)70Ox`2^qpagtW9`h8)|0DW}P!&hzUnkPefp_#(7nnmw2q=_t$vE|tS4zy^*=2DGyV}r zlU6QqyP>C4!cd6gbb$HsHGkn}8G;YAyo*J4(jy+2D+&>6iAl@fv0fR{4Me<9X?5|}^dGSN?@3_wIqVBMoNF$3bf?cLDS2>GH2LVlJ z4vxETH2C?OK z>5tN-L-XpetKuhcJ8_>GRU>k>hH^E`cGAUiBz`VG5;o7bs(G4g4s_)omo{GtWeNIj zCmswf4_Yps<@23(|Ck9qR$3Wi^0GJP0mfM}p=}wV^TEonAMPwtj#f4?6)8YL6G`Jn z$)Ya62}66m!C0m%?^T|8>@LnJQJiqjRgI$D4P#i0F{Z10;ru@NJv_DBKNsxg&jm|y znd&*v$0K+AUoe%JfvNQ8Y3B}3yZ;NO(%+wUt$%oDLSA)TIhAZZ<<|5DO(vL$wAkckk_9a zpLFZdTaRV%o&e)ZYxwa%T1N_ZzHW`AaeM7|S`lDm*L{FQyN2??&IQNLJDACDt)Eux z?1m~>`ninvcQ7Mn$r^~+Eo;QJ;5It}?3QCb81-&insK{W^r&f4KQfL(X?wPfj}f1S zwXuI#&vp^)KpF*$UUf#TX;Oq9sn47rzn9rt4pkkPMQ*hIIE#2@XCSu-gn}ce7aTm{ z8P+;KlpZ`O_7)N#kq#z7{OCeBEIekn9(n_YVJSEU4{9viyX8u`4GjGVPQ4ebgC~_3 z>yop;wgz!}oKqBQ%(QWDs4%~0so#9mEytKdvrzxbL&?%vKVRiivs<>O^-V#_DWcY2 z?zCM4<eqZV}PLp(R9A|$5ihut*?#13YhaduA4l&+Zef#_} zsCyWA3ryiZ7tp`9xg;xSG@Y+P_u_56bH?t-UJh>9_17wuxR*s9)N|dUa?|MGJwH1+ z$WmUihuW)+78@^~RFrhREH99L9mj8Y)oEkB>J6FHteW^8oG`00#M#ODrljY*Q8uI9F#O~9{ zGh2eQ?}_x3GP-pX8Obl3sKpipL%wvyacok`#o;(h=NlG}+alI>{Uc!H ze9N>X+X2pksZN7ptZL=cv!gKCSRqecWCD*EkMpVM$xYJFZ?SF?Ih~7~98hfLk}t7t zqInnuXECQt+0|fSzpchknHs6DC>e}S3r?>gmBOfe>77?c`nGbZv-bk0uo$7*l2>qN z4`L1yT&B`SQC(XBcoh2;MfS#*lJ4R2#~ilV%KEg1kc}x7=<*%1+48`=>!CTG`^%#V z+|HiEtj)6iq)#@Lh&il$4qQ#%)(D7<|7Z|9t+#|}ic~l(YzOUJputLqaZ^)lm$rnG z2r<_vw=hGGwh7v!_%iggX@o`h7T(FE{)*rx$UzL?pS$S)-Fg47!~lp`p5JG1KRd%juZTJ=y z(fcSSt)99I6r=XH0$u@YtH?lP$*<{}PfH@#4$1P!5?>O3ujG46sHW5g0ySw{_9996 zTSx*#qeRpx799P0^T6iG5|x1wbukFDa9Mw*>@FgBsKP-&xjo+%r;Lugiix6$DLsL% zYI0Z|#-a}O2Q3fypU~Q%YN@?=I$X+-3MryJIRyipey+ML!Ew)P+z<8wz=no(^V}zv z-FiCQbiG=8Lq!uYrItGfI$H=Dow)Gy!cpBUH#7FQO}iht*J_WxuE>x}`ci#_dmM~Y zYMN?0pKJi*TFC^o?3QX&#r26nt8_ z{_rd%g>%n}#mGu_dWB?KpM@&VInA-n9S&~C*?SLV;y-QAxNK%qg41$^! zzBm8PxX(Y^O!k25{(mU$^UoI5hYJ@KD8ENx9ZxFykx9X?h1p3Nr5mMqsU?>1WVGZ7 ze1Nn)D9zVFrBI1T;mVzWqa@2}l%<}ZmF{-Ys!uBjb@unA1$7D?R(Hpqk(F5vf1_=7 zmfrf1_hdNB;jY1SYB!-I<;OhiBlnc%K9&2I26L!{i)SWkJcc36SiP+ZDVNBGG78*E z(%JOu{H6vmM#tny-J=Hsg0mS(H$D?~#l`d=RR{WrH5>JO_D-}*hMv3TX(D8H<^x1@ zlL9WTc7EcI1nwQF{^i~PeA=w%->9I5QOqaaxCGmGACA^_Y9yvv4(A`uZUP4zW;61D zLC~mhVV_H4_3OKz+y9lnx!B-sN*f^TlGTrP?PfH|{p5(A@{;2L3C7(vzex~>Or3Ht zLF>!KZ!_hopKXp`nr;q|aaliKSqh~PcKg*w`<=?`WxMNk=8!Acz|+oTbL#p%uz|Jc1uc`aI^29@6s~s{AB0JnFaFJ+Z3?X zFLNERRF$0JXPQs@BDCM?V3tuX=YXKm@BxZ-s-u?ieXK(?oyNNx6#NG3?z&Y@Yl1qJ zj{Bu+KCS#-Cr3J*Oel0jee=) z3x#_NRt|{chJs$_e~GwFA4tE3-wzMA6)q~dLKwQ*yW9pQYniQ1xL&nqST#FbJ!(^pb+*QvBlvt$^oDJ$ zywDNJp0QiKzt|f@BOSkrZ^+XT#gty}i|aP+EI7Nb2mJ!<^OCY3P%1WJh$u&?92i5?#~RnvOJ9*k(rvwR5(uN)AJXbt3iqb) z=zpwTE$(#P&K`Y!Y3kD`b|j?2dfYi%p(KPW_+alK0iifnD(7}!+IbiYvSHJcoFuYp z{=7iqa;|d@eQq0AErx|cp7;SI`%C>I{14 zS3;j~oA((JZ_Uw_T;5>x&_frUaE4;lzezqA`fXsj*?-bfELEpB*nWa2B9KO~7!6$~ zVsWi^S)ce4%1 zaXuoi7cd_I5dRRI8VA~>!I0)c1J(OYv-8YReBug6}%!_t?;6046*!` zBh&wtBTKqp=z@B&%&C7bO)@fG)N5<=(tx)ROfl&^Nuk^-#;gu&aqa=Z5H=IKVq#e~|Knw0-k8zz1!eF4!-DZk+cNtbphS z)$_+>f)B8$17$$_sLQQsLjJS*!bLcgEP;PifcPZodpZuF({bxNx*q@ye$+fbCggjO z50HY(EkIe;U+8G@@^fymC)(1-uMH$A(J{p@cxH!B<`EMSaJ4ks?U znDInluz*T<3IR*f%|FPd6gXdP$<(c>WSeJ%Wp&E>TzepVEJKAo+no@kny0<4;}n9U zPgRj;G1#tLY=l$!>inWiEbpM)Wwx7S43yi&MTLsxt6W{?)dd(JfS5g7A(k!6e6kX+ z)TB#piof=UvcC}*9&zo99M!z}em-lOLzO2F>N?aOlMKHK|8N2S%E~~N%J;7AG`@S~VVYr1>?*#ozFQoS1Q7T@D>XOG`Hg_s1 zg&FFKiEt_Vu6_{Y^bxy#0YI#unBn5JC!~T#e>@A+0bk>N<=%~d|1~!%pWnay zr~fXrN<+!=&C-|N4$k2G5WR4$;v;_5FAu7gY9>LMA%Wkbur^lac?`CtFi2Zt4d^U( zL@HKZVl`^Opq=>v?om_p@j*C;6I>oAEH^Q>Og9xAh31jzRKn{cTO=x3nnG@%p_Ekb zfrF`sn(%d#8t08mCF+0{lOEB6JF_(9apN?XPyb)~O>_u*!#QoN`?1 z<0eL4?TS51FdbB`@(~WWjngFY>oCd@E7zpaTlpb$LMQR@!JXBLBd#9jn?Id#Nf6J+ zIOCQVS1C5Ug+zNds`mR>k*O(^m)sTK-+RitQ0;g`9Lr*OLnU86YRY1$F0=vMa+X9# z_Z?1It5|;XuNZ6`7(R>t1hn{P4);IHmH&Spy#u&=bIymiAEEojIu+wA^Cv9K4?ARZOsOXh$|> zEf&XNyM=#8h+Y_2yEqJ5`PK5Wtd@ob+Hf14#j}H|I7(zrAf)Z~2ty+CVBUtq`{z7l zJf)oTs|MJw?W!Bz{B+3U*?=d7s;w~xb;^yY3Zu{*|hu7_j1s_O#by&FJ z)w3ZK`{dNVcCX`yf4LC5?) z(nzfGq4r4NeXUQGvK#~Ich`BkYV1nveoQ}fKbh1Om8Bx)wD>@DqdkWnln$sbM@U?9 z3ZHx`7%8wFO;Ea6$9%!^nhGs5_#e6ip0AkU#44!rZq3eA*)0wf78F@NwB~c_*?0YN zZ&R^6Sy>>+bIG#g98nOTK`8M4rU*`Xi!_AxaaRFK<5{=+ncu3mBoC65AOz28vn>8$ zmh-!d{QaL!55Ip4%E+87&hn(QTASTU`fR(xuem+h4hjQi^ay)vcVIh!mnT_xET)p! zZFsU%a@<2sTx$JtWOA?R#0wp*N4fVvcj+RMoxQqS)_+n56kw~G}c+84rzSf$B9Fyjzc2b>J|#~M~)c;QHv zxs-Hd)P8phrpBRpZk%&zaO3UC6`|9uwXt*zPQL*4a>ZxjdW4?g7T_3JBi6uG@|%vl zL>@H=JDxXQEw2sfU*1WJ+ZhI}mSqS3HwwP#0}D z+^tlQWO@>OP3$!g+^_Y#mXzfR^=!dfneUm$_rq|-Yk|sXW24vH=S#L{f<`=!?%<8E zB!Qt$7&zo}QLbnP)O_*riEWY`7IQqVmi4J{*LGA!pt-{~Wm37@8I1irz1MIL&hPbO z3 z8gmy3xPzbTvslK?Pdlf|B5Brj$;vAa13p1U%U*AAs_vZSTI-^lgKCpmhaYQIH58-W z(m3hlmNR@EwuWIxs4Da0#JzgEFE{38_pa|fnnhxY0MLP36>EW8M@+ZJ7ni%}bG8of z9A=JUp6+v_M{dNHz*xbYSA7qUS*kf5rsTxkGy-wQc zmb)yT2livm+t^?zPP!(Hmx512&!Zm3ei}ra)Jq&Yo?KLLX*Hz3{UH68G3rBigC6=o zwL5jvG*k*KG$9%=-Du{8klwop(Rp1t%^BNsq4$Wh9TH?{C|rxb=`ik_IVc$6V8&E* zh*&)V6&(RRe68;#`g>ka?^PpUTTWZns;~?^)+H;S^%u2zUpeOF=+7tL51Q+u#i!mr z+BKp%PJOd+(r08=b8Zd5ay4yCeTV5#hwfeCq)}0#q)DoxNKbB_J;syGsb_I0Q1h{r z$Bw@^G}$`wmQPpSkgYUf%GI_&J&iU?n-uxfe-Jzwib!7!?0VV{8%Wr zS7Q1X{T@nXnIfkgw^KK2;F@I?iVL!2bhc9qx&0pd7(yFh3j6*BRw7bRM)kr!Y7Pyo z-80t4>j_AX#sI8=$sEk}OVH5RjF%@^4CKzRM&TsG$hXeoaKf((kQ{S$#UBNuMgj>K z<>C1{i@Qtx&>Zdd`8_Uw;{}k=X0slT^C0^}Vs0 zo1J|kf~n%3#tVD8(fKB^3y}e(t6qjSEZ$qeq6HpPBp^hv`=dTzEl1V1cidW2so3aT zS7fHS3*#Bh|KKZFt?8cHNw!WX(p(zI>JL7crc&U1y7e(2(`ltvcx#&P)Fb`XXPH-B za+XUwNWWeaq0KosfP{&*C=&^k9p<`CL5^x=;a$PYg>KYRxExl0w#xazA1%RW?avPG z@-+xO<aIsc50Uz;&+*MIv^;6GQgPV6yb*82iKE92+zw_1^NpjpB z!UuVE^G{wpUpm#dRoy(?-KbT4>2!{!YOHsI{NmkU5x*N`+`@9aTRue=sQ%`9kpMD+ zmc}mFIhPbjkw-5aorCZtBz$V3aI)GhJcP&z0Gr=Rl4-(c3>vX_2bGUi1fJAhUk4Qm zj>`k)p;j>;`Fn||8fACW zlEBu+*h2?Ajys7030P^;#KYo&eJ&>vP7{`9*2H{o`0!A#g>>^$?ikl+}6;?P-@cKkz^Ku^1X3l|ab?o*ka$dq?(lB49qd5prE z*U+vFyqYji1g1O)eoZAg+P+n7oGs{8KZxkdBoF_ttJ+!1O$b!Uu+Z2EYTpi6`&C%g zPfM6jMk6enKiJ&sXrn{(9C>pu?={A3>n)(!Jm~vreYrB0e)?S)O`bq7jwYBDeYu6pFeVS#uUZ%!hdQ4)%8U zC`h^{3u}kkRX>c~&9mUiAW`$bL%?U!!Vn9$jmu=5Ejn&y@MH=eJY3~~=R(ZY7B=%b zFqL&AZXG>w$jBnbFj*2tJ@%)nb%Bk|s{Y!2bq8^z#!g@De8nyE#DWLcG?`<}@cfJg z6ebSY;JRXB4i(0}te56bOImtgG^OA#cM%Uv*G3FhF1FHNGOfpnzjwVo8^o0qNG0?MkB8f-!87b zFsGMBB?pReCb)krr&O8uq&E${Qr{oN1@%=N_H5BwYM>}h&wi1UxYn8oV+g2&ZY2s8 zYNTBY=>$~9SCEtN$mX?8^pL^mp?-4`@}(h=A@W@<@i&oxgkp&x6okbUN#{c6VF9o19Hczc6T}o%wnwY+LWcKn3Zp9NK>}LUT&!B_?^KP1FJ!i@?(Ps+uZv>=VC(`=i;2Rn)$?)!X-xcdy-Jd@^SJ zyWVnW((D@@x64d6=25t%LQHaSzkjrQ4vg6)f)4&mCCK`)k>)|yAQl=Kf`F{2wAiP# zIKLVG0~-HKkf5V^n6!Ddh=8id`w#5X1MCr;FfaW;-6y9#M+uy`Lc51JY1` zG`+}txvmH_BDluGFvUYa)7nE+7BsSVlx&BR{(4d9S27}``MaEmA}U9&so%7O42U}t zhHX7z1n-gT7X3Fz0c(w{mgJ7l8D|5KSP8q|BUz$tB{8GbZs4T326 zZ+=!3G5d%UXnMDRC|svl+5yo_2PMrtz1u&GKy}e4#r-?x=0<}w-dJadyMjjg(%`Zk zg(Y7|mLTJ%`mcf})vk}B+;M`jJbcGGri9#F2qM76A!PaY|rH0cZ|04-qv5+#Q9-vY$z6Y#?HD^T_&B!A-_P#piG?FXo>z43zU9!Pm#c;F`l&g{!``hYpW`apWa z8?pq6c>59v5tW56muh z`?n|Ho9=Uwf-$C~!)o~7bJ6X0ub)Hy98NzD#XmW?I;7+HUPc5>%)Z&*9>z zZ$lAC34lN%a6duzkwPK}W%rRnGxWkmjD)3+qd<&|`wDM_NqPGjw-_en{T8GVa&hDo zLqBqHV=tTxP&*_tj0zwvcseO>Oa_m%djLd4l8XRTSeVCL@D$H+63EdWWxxdK1M{YR zAWG;XbqjX@DCo*sdVvC{zkUHGtS2V+F9s{REwxX#&w%vvG&{D*kABdR>jLV+-CY;3 zONVKAKN&K3KV1e9Ea+jJQAy%7lO!J%$>O9aE3lep)u;PdaMzHIe{eMGjurguSDd6Gy^9 zSoN+)Wd(I#vCW{?>z`^aL7CTQWC48O&4d^mfGWA+ZBmqfuCx4$R|GbX%yJ6+oi$IM zAoxgNPnTH0hcbmNPt4q>GD4)FnQN#qhL4n@&i)=I<+ABZXL9j8?DygRm<$H#({L2e zKgPHS_((k@`a+5rnb-b(i9)=0D(6@v;3W+$83x7kL5T{G=VRnJb@-28A&P^KzpopUU`VkLqA3uxA%%8G4L!b z8*w3VPMt{L@~av*3H=@j7?#q=17@d-MxO;g4zonzIkTJ!f`eu)}wHsKoR1?h+E0%r91iGh`U%7BCO!Kg+v6 z!#uDXfG|\P_s>!P5R?{}r?zw)~ORViyu7w``Mex>QZ^1A<3DXSkUW&rZGzA==+&PHoeIrW58mOgJL%fzP|}+iu2_o z>i8=4sp&CuQ{g)7<ZOqF`$OEOWs588ME-lL|P99NcBeuGpx0Hd}3Fxa*PBdZ6BD z&0==qNJPSC9rBJ=PR7w%P#R66P%QUFCT3W;G3MWhub~I1Jg;n`GBBFRjCcjleu^0b zpQ$Et<0R64k@TXP1K(#G{rF_{_S@LKori;QLcKHkXtXkNH^k0{7MySZc+AzD7iWWT zQ0?r*yXdfg)JX8WL;4cgDfWFA#YE1Ipk*;#m(ogh|oxc=0_*$oSl2)>FDO_ZG#(6tSPrHTro1A zynok7e5U>PDpN)UJ^Iwr$`1$RZ5ZTQ9a?j%)E-DjZ_j7t$qTV;N@D)rl*liBW-bAw z4V55ZMnb*1V4BuO3>}zv@nw8PFO5c6b&!y)7_d2I@kuhubgG_0kx{d=@7sbiBuDm~ z^zG5Q?fOI=&T?<$z|7sh6{oLH3prB0Lr#1&J2cw>S%4|w_-jSqOWQWiTB{vR<0OVV zM?;DM-`YbMh=a+0J9m+jpU$1~Cq+mZTlsQSqBoh1H&Z4u0eC!eTuPvG4Fm^{QesMU zMn04zE7UsxC4>C|dlaLq*5#K)rdCebic2Zh;PB*+^LMG>V5Z>Yxi_TYe!_s4tEuo{ zS-8pqpw=&{%pJ}TXrIWv2ojKA!x2~vO}+KUcH#E(7y>YQP!%V946pm>`+q~OstW$Q z@hZG&#L>-$BaIs&S(bd2l)8n<(W6OB(HCbg+CwD|p1#Z?4t#%hL;>^1pppI@G{CI= zW6=H^?h)L@SvoeT7LvsHyR0=-P;y$~H@0cB_lOHZCXnK%I`MhhCOadOIus{*B`QaJ z=pK`V4&3ix6jAtRFpBUKKyZeImgn!^=ho{a&QnWeZunB*N#+mgP+z={N@OrknB;aH zv4kd?WGMCnefBc^pTv+imWSKURy#6jx##RlUX^;`lbq0eolRZ;4&ZIjL4M`FafQpH zoZe4@+x5|W?{Kcf+*Krq!gk68HRuuQqw1*dJ5*L5e%8Nq*L*0?;zqzmau8K9wj1B{-%a3o8dgtKq`MB4ALD#5+3>qx2Zm|=RnZ`*rB|q#0X>4;K z0;kxwo3J%B1k&#cO-DAZN_T}7YTJ7ZUv^}t}dg&qXi3e-t@*i@V!x=3{Y|A8O=x(-UGjmNq;AOUGBExq^vn z`6bBgV1Bl$zptLKc7g+U*~*NN%^nzWjPZfg0XoV9XY)Er#az2%|E5)_QsQ=vWsp;0 zdtyZ7QR)Z=Lf<8 z;~Upk(-v!=J4REPC7m`QL0>XB*GkV1!Tdtm8U*fKCrMyv&G0CJz~!T9qHFY$rn<*E z8;W_Xcu(FB10mAA7Lvo|<7F_0fU42-vH_}ZDg3T!)lFj!t@r(zk#^$6k*4*gJz>+E z3QM&d@7qbeGGredhJW%E{z}j=DdnEeb%bh4#yJ1D8&~2i2pw^UGt;pKLzW>IFt!vG z`WUHokZtI+0;NLP9vwPFu$J6cwnMqiUg;{|@H5;+Fn%nbMxMLs=p03Tpq$5XV=kOX zzHIQgoFm7MznRh_wQC4^Lx}@7R1{Nx%kBfalIc(aVEs`1M`nh_NYmljMWhRT!ImCc z-HQ+yuDB!jy$$QvkcoL1DzS+p<8AD*-6`x=r2h>s1FOe5BJ?0Cy;cRqv2XFz(OY8a zvoF`-;C>G@1*p4+Gg45y<8(uHx>s$RY9$PT@-gZ@?(w!b)dax#gp|qH@jx5 z)ODFea-`7wX*DN@tFxvmYuYU#XEi>a4!7xeYD*N&$V=&ZADj?jfqT7@Vs6*@oQ*Xr}J&x<^e7*2syCD^0Mt z?yRZC5SB|$JefpMCx?SG$$e7YR64Fi``L{9J5h6ZR8^-g%~D0tg{?? z4UFHDk*OKF=o9I=*af#M?XPW)6>p|D-BSk3^#1F8yt!(dc(9%>A9wHqJx6 zG~b58G2UL8CKxx)Ik=gZi#E&tCXd$fDBw}X7z!;jk-dV;;c7Q$`>}JOfSrj z)%Sv4lB+!B@_F?OS%C3m$GWLkdGM=Vg^nDDa>8QvDOHzD<_Hb)Xx+}qwf1RihxFlb zT?4(*J8^FFv6K{RPT;BU$R={`TJPF*Au2Yi`rLT#amDp=a|!Z#imiBsWi#tm_x7TX zS4Po8Y=hH?40zl31H>d6eu%Z;8mI(%XFx*{5 z{CrSS;+siA9kHS#UpVl`>tfD^pDVkiTx0@>)k-PC`++ZZ2M@bATCh8&M_VWv+aYen zl8UCML1R72TX;z;+}I`y^|ZxSm$Ba5cB@aJo|bmWvn4!OuzrmSuz5xdTMR*N4jHVT zc%(?9H#8`~I{wh`ZECP%R1b~7oVsDflWZOrs6a|YwT`7a=-p@xUmp(ijp7 zRx)S#hm`MR#lhIdYPY~_cjJkH%PGDPGmtR$2ZEB&CEO4#KkUI0=~&H?yVoI{-h2P} z{Gx55Yr5d-YG#!PgSWTIcQOvA|5D$v??p%X!%Tnf;-7-cJ2iUfm$s(`P%YnK9(O&) zBVC?k20%*uEDHhwGEIY@#I#7qXXP(a312=?l$c3Qo~o-HX`hRXJb{wZn#J})Ry(T( zHg=RK-ZfqIUC+yoLc}Em`V!agt*dk=XZC~}tkXgzk|!SAu+4-yzp1p)ag92k<~#Oc z?JaE-+y~8ecO>NkLTu=0ZxoGp^eIN_uOK087e=KzA)1$q$RQ4mCC`Aytvevz(+Vez z9@SOl9>qO@dLt{mc%nz&+t>mt_LoqsK*|MZ@DgxoGrxkWE&n2peU-*gt@}+JJ3ZOh zk)Qy)xVzW?L=zLLz0-5B6#Prd_n`}9KL9DxVue-O;=B7{6>}qN*}(dO>ms#lt*hrf zoV%Hulr(?*}D*kbXb+HFl*Ei zqVK`K$L_+xqbSwSg5`eOBff^abTupK3VCo{nl8SHV)9feOF)_7c`q)>uQtn=KczU1 zW+{Fu7eT$pzr;G~7uKhiA=kVK3E||dE;|c7E>nB$L9^%|7uPk8AEz(quQQp*tI6NG zUF%3%w_e*U&8YAahkvdrBgEG9Cho{IFc}By2)OS%=IY`z@+477^7QK=HBdL`h>qzv0Rp2dXT-ReX(EgGbrK-bgd8 zb~9VU0OSoxR-wC5saClzZxAM85;wo!hrYq2O0l1K@zLkk3hD`GbDQ1nF2bCmlz(XP zP(aw?vmv1A-~u~I(E1cIh8$@dy3jX`i(LPRIzPD(^K>vg($OOp{Es>bP=mfWvQNhZ zaiY7%L&=@O!2W1@z%MWu+XZZ!)vhMCUu&=wkJ7m~96T$~@X^Prn-vJTdT7lg4wRBh zfjBNHX}tW*jfy(Z5WlQg_`E1>;4(;|#-A7r+T#K(Z4=A)m`2N86H{(S+psNMA?zoE+6!*(*5+|D;Lm}Mp{j8)?tkPP*v*4s6pgp{AaqL2Sg)++PX zPhe5-RxGCDe-!QxxpQ%1_Uo+3s6-8fyHoKN@RlnX#3i~c6s@7wPnp2w(=Blz2?$9e zjmv0t{CroxIc9`Jo1%Yk%*G3$veDtZ{pm+t5LG~Ia<6+v!r4gm71GUtVnG(jyKJq)4FmZ1vU*$z>F)_n18s z9aR%o710RhA^lYdt8yQc8gn+;qW6ztw^o9?2r=d~xb54{dVRWGj5wzU@Abq-+5s8r zi;V-xk<<7IC{Y{8DW?+qA(~Xx$Oe4)q6%f0QGuobT@$8H?uGbMZSwE}A=~?`{TUHbFq7T-SMo7sAED(P3wkp=(7|c_NdCtQX8@r;??<1P5(68nDc^OgEae_N<@dVO1v zQTfj76R2vmYu{Mr$k6vszf_}DSz<-HSd&q>sdZi9dYhg;PU_WhzW5?(Kbj&NY}Vzg z0|Wf0REIy}N`19rgziFO ztm`Ugk0ou!c$5O_aa!;wM``5DRkP!LrOHmufhB)wBGKLUyF7}Io>l;xuIZ|6JSGF< z$ywse;r=X}xVm=WK>k83Her6|jF~wm<(9FoJBF_N-H@@${^~nx&XTHXJqD^#pM$8H zg89XW&E6F=Hzd&k4W$BjVEB~WWEL?Nv);3G>&T7;vMoU`d9xiVWZkU6=()(I+3i%6 zQPGOqF)M}U8L*Hu_R&?IZ(8Y;YX5~+2BqZ9fEG>~o%h4rqaHdM6TT?)P0s}`7lASA zlBoTPC8#~Bulmlz{zbuV{NOG}AlNOQ=*`HT0xPdyn#lJKLJkKGqOC+M1dmtE)hhhj zN`=#&z5zPRd^0t(paBVElq-UMvM*IhX#O6)o=hAg_KP=im?!eT2_oCFDOBS6fze+2 ztO=q$$yn}KXM=sKYaOyoKgJuJ?M6|~ZRnmz1WPMs`jn8mrM|Po^!l~o!@!DC-B6F^ z0qF%wIfKGK?-Cv2j|JDhW%iAwORF+Q2!~??L!4Y>fSO#;bd}jty{FR)hPzKHr#vx@ z;G{<8*zFmNmW#xS0`a5oRQL*Jq5&a{Et030lw>6V#=(LK9i$_rGeGqj zi}LJ~nk!?HQ2dq%Vq|4Nh`$P`;Co@s1B9WufFfI(6MC}$WcpAZ z>Apk~>h;Gw4S4)g6_o5g-Bl3s>6Tk(`_ zl0pXJUQz~9PcYX);$!b3Q4ZuhD2pT?xyQ@JhAkeaV5Ltbn!#nRuR$Hao&K#~0^B>> zUk|=Qq9ZmGK60=+))Cwt62wJ>1o-@12b7{2_wa1N1yG_Ekb!4~IR(qDP(CB?-!Xi5#r9tQe@;Uo25CQN~Q|NALO zGY9kW|7bY>JZBQ5;>|>`SDYyen#XN8(sf?l2)@0d-W-XU17BtuknlAwBwufrlN*g0 z?!H(z5#(2RCO%>VLb6{`}hilS?)7 z4%V)pM-%D~Nc81y`$!mhX{-Nf%0}zrNY)wI0>)+d*83=D)!i-UTy5p!i+LWgD+JgV zSu)=EEUNbkj(N-U2U^7=56JB{m5&p1Xo10tdmx_Bc#71RbF_j*5s7Gq<5?x*0gN)` z{r{x_|79fC!J7R)GRObRf&4BCUr+Is4esnxPgtPjkUD@l>O_p-Xcg6nD+Uj{Ow8|S z-=q;cf>)#UlUsa*(RKH5`m>y89DPf&v79sl&d0c{8uiqLpwbHM$5eWJc>?l{mlP*w zM}+US4UVKmq6`%`j7O}$4GYW=0XU=o+?oAlEdE84Rj7*mA8=>?{`gU0P<}MlyG)cna8_g-UJf%miJ}K9Cj94Rvi^ zCJ8!s3NIjHQO4jg&1lp++yVk=em{oOoew*PP{QwnHczA*PI(?X!Pg~CBah$%Jluc! zi2J{MgaZmZ)UERU4c%%iIj5Bm0lV4y1F0mzL?fJR(pm3!MA0n`t3xtO6)Pikg(rKQLv{`>B^7i$VNX+9s}@8WT^uRYsx7m+D&DNh zom?DPo9h{k)MMD_4@H2QEtv#(Ad+BnU^16S!)-A?HW20~8BW?Vvf$?LXtUZ@veczM zMTW>GP%fjD9HSrpuE4A2ckd*?DYpT(t^<4so!AnF6M{>E$) zzdh^8*#=vx@yA|FAs2^N>SZ7OG00lKbx3Q^U);7l*~NNARJ}vy`T?%-bm2PXW$sW0 zWyiPVsImJ*3_8@x<%Xm?Y;&~`A0SG&XKf0)>ABX{(kow>v`NHpyul}aU_R_mzkVfS!2^`!3L zF@5m2$7x5w5dtg8@8jQa*NP>#773+&mUSwhRTQq$S;fXv?A2gz9uwtXQPSrBFvX3~ z{+6y;Jy`>&gEI?TON6$nA4KS!TPnv`d-~+ZaM8`ch?ySdDxekziWi$S7{90D#=Am|(cgAhhG261$Bq*?*aaA97ZJMbRG2GBC@QGeB_ zbGj43Wq_VIAcJ}8nEURN=_#_h;4G$Bx0pY=SZt|g^${BHozT=bUB{n4i3)};ALYHT zbUIqUb>HNrjY%*ni0SI@!FpQH>12RY4i(lkx)JOH=T4uVGVL$PL=XL?u&A0x4Tesg zKr_S?=WI=K$5QIQ?-7phc4XmGMK5DG)tK4_o$=n8iI%+lyE1(XJ{+PM^q=ZZUSV>m zRrBuIxgC%mtg`vk9ud;-$j6Q(w}FGNnw$O3yf3$r@LRLskBe>o&GvYWc<~wyq{42n z`*-O#b3%QY%ig3ux~<-*?+k|ArQI;IjfoP?jO z+rgxkAt3WZ+f6W5!=pq3WjYN-@_)Z$&~v7Mf~c|w<#F?`)<>3iSqW^{Kb2p|;-U7( z-EEXlT9Iv-Q*}=Up^0dx%+xF=L~kJO_SxYYl1iDbo*qPN`Y`r$gR^|qrFw($L*2fp zk288{bsbHt9v7zvHK%+WFHg3emFw&h<4qFzgxeqsuYBku)0@fqqC{5*=VsS4WMZ)^ zEzXJN9al*-^l1XxnS+sVXnpQ+8K~%+w?kYZbN1Rxow8Zyz7}s6FYW<6fYM!_N%Z?& z%@6*qGM{R!zc4D7=-?Gw9B1qHU`GgR3O#W7PT!v-*j0ectWuA;zudRMn6JDhsa&=q zKfzPf9)Jbshe`^Q?D8D7l>=)x*}cd&s;S%)Xq;}W+wP3tHl8S2E>%II1bfHr8k=RE ztp+%Q!6fg!C5g6OEUHw%C}wpp@zNPS-kOGSV|9jXd23EOFEqJp;vP%@sfw0Pv<F?wF{xo}C1-L55Uh>p+olHHh1F zd*a##3Y7{8KbQGyz&vzor8XSRN>rT_cGHBdv3Bj>;uQU!@nk90Gd@U;6KO_}9lF~9wm*YnKYbyEq2G#Si?cK!4x>-lVN8>=Hh z`;DyR2bpE*1pAN$d>e%w!`|bT& z39IZ%mP9x+fRkZn-K;1?&z~!*6yCgyYC72pN{u|r*UvVhQ${K)cK5$98715DDp_^ucyYo(Ex*?|ScKPCs9r_N_%bJhsS8-N zy;z!f;Ou6eACTJ=DO+Kgn?2r|yA8zi#;1}69AU}yyT3(QeNt#U`<&Wll9~}qj$MYg zJ=v%-F`o7~cyV>w)|O{hWSE|`N%?qt?oM(PJq?d~G1IGyTVQ@xXTbWK7v!(ORD6&q z?0(Dodq4EAokJ^YquCKxZT;q5Qx(#5IjWF~YD>Pp?WuAV6mZ(|YJH5$9>=oW>wa6c z()0@+iBLHPHnmi<8Hlgq?&pbu-VASrs;w?gkh(QfKE=C!^C@{&l%U~o3ZMge<(!;& zhv&OoCMacUNdi_r2G!h+Pk{Vss{Fzg-vQXpQ)JeLYu>_xtbbc5i)-yk^rx=6(Q zR)l*YJNslsjrr0XB;*7Jcts zeDEUrTmzckwZ<(BO##T*7!gZx94E=);3lhtb2|T?-~49TyG(7!wqUKjSfomtIFc<- ziFW^?zpZ>SUuQ4|sQ~=rU{}VxT8&qQY6w$h1~z8=>TAPgyr`rCFIS-l?j)mU1{e0} z+UZ&B&d0>+!_aLIY)v-tvE-$?PsRP<*!adsXKdrQqZE!$kw)eq?j02&M<{Q{h% z2njTb0JtyhL1>RHZmi`{^VCa)DK>MBSN&m%xTyoafGul zq^*77I#XsK_h>9fVR8LSegwn8hD^XT53MXAhF;%?@i^kbcqHPc%N2Kk@Uf2`1H=W! zb;^A!4ewbT5+#Q-xjxnyYqtC~9O#uc5$8}Tu8B-ptlp4gLdM%KMAWYlsKQ(!z1;gn zYib|wHICu!Nd4KjAI(hrlZEd94cK-Q@Q{f@bu@5tertksJNM*j`Y}`5mubPm_=@G8 zF6DX9X4Y`7SFq$`38@**Ey}N|H>V*1;~VtPt{YpqQinw*Nr>#J%X36yrTibAi=Y$c zvrHwf09+1OnfM3og|kF(02>_sKS*5t*I4hE+5e}RtN#*q>Gno+5Np;%I6Uujd!Pr- znF^?m7gr?NvOYBn{j(ik-`l_UJ3X)8;+48||qn2G9 zSMokPN_mleY;KpncyWpXurY1KyR5`)ts#LspN@1M2k(Ld?}YE;VEm2Q#_L8()O!NY z3~-2IWUR#H;S+z(0iiASGMd9zeo|84^L6J zTsN1rIv6+0naLq(55t4&4EwR9v>hsnNZDYtWOf=RSdM}M7oHj}rp@l-Qw;PyiObxD{0kYN37GoHa?Wj1C; z@gU4wv~J&$8oq2coNcKiI2T{MQNmrR+!5-(v;4ezDCLdI(vp4gqi7bCkQLri60YYj z2^7oo3L)!_HVniyR`W{gny>N_O4wbZnBRBlLl$abTr1i3ppR}3C&cl?JsVaUC8=cb z8LcXwg#L_*GJO9>fuoM5cIOrDTHV`vq#M4EeKR<|i7i~zBy<3 zKvAP5A}yKPPKk!{ODQtpdv8y25(=|6ijrX=Ndo1H6B8f#R!)&eI^;G>rZNp6EeTZd z0^=yb$SOElKANR7@lT36rL3&) zfsZTtDs<$D_6H~k@CYydKu~sG@qoV9;^<42RO4D$()h;9Lo9A(-l;bYpYqsq+lMgs z5_d`C$s8?NE?gG_p!cR8o|CmejBK1u&-T;#KkKx~gder0!6H*;f5j@dW~*A~zG;K)j$l)pXTE_M^v)eFT%VDi zG6&P+-9+inZ#If=UUgC-tu3JSquKpAy{=-*ixnDGTUYhm*HJpp1bX~QuzR7`*4!|Q!}J8&b-c6D51e-;AU||7s7v+|1kchEWS9&3(NVCYuoAVzJjlA3AV^i z{lc_yVMmsVCIJS44l-;)@Zl;quSoBJl3c+!y2hOnG z%~*NUtB@zVgy1_rk1;y`Cxl830sZu>o%|2d2OKWZw9#FDL&EiFg}j6NHztgF_ZF?I zF&n~^`;PUb&GK92O}{Q4ri`IG%P*Y5M3d^B(fG__cS;&Qa#KmqnK_--zJ}!fO+}}jzd~5-Vqx47$XP!kEhuql&3 zw|5dLRg%=1qdSWk!EuYFgIu+AQiBJ7>7cxRfIzp_;YsRJm!`w?V+{@PtvhFqsQVC` zbFJ~kDje_rR-K4K(@t`eA`*=7@EW^IKy*GEJSx2w1Z^`}M47Tv` zsxFZ>iW(9fg63SWC>&oCMBERbTfe1Rtd*K(d6;w6*!ayJk6d<|yE2S{un$!wUE)3> znUFxSX30qSC;ia#gR5W12<92?KHV5@BkajK13JjYWG+ew;eCk-iD61#?fLpCzW7PQ zFL^973EV2C`>$}1QmZkdpJ9pH{g}Kb5l-3{u5!^L6HD`Sl8DSlNSJ+bt!}5$t*D4H zK&{b*=Hg{do`dSdMhA)kxlVgPkr_Wz%x#=9ZR5MRuf~hac4|=0wB37>1mi0~$5vSJ zuV|QvV;lI`;*Fkzq83;L@aQBD(bb(${X)pHeC4*{YPSy8+y_NB&>I#n#~4yxO(>Z! z&lAF`;I3_zG?`rkoTz!pA42hT%n;9?+e!v9@C!P213Mb`^;vkS7f`fxS(`s{A zB@?PfktY@Y=8Anz%QA>06U$9Hm?Q}2xWD2%^fbz99@DWEj%R6NlrEg&b%-)Jw7#VL zcH8qDV%}DkEl)1dKZ(il9GC4i<%F}ndC62?(xVV%t0}P5_svI^^NuE|TQ%C3 zghDfKuDpEL>}UImEH_pZVR#7m&Fg(&Ogp7tC*V}uE*)t#RPPnSnG7yaa0_UbUOD(5 zNhf&TM?aQ+O^nmLU~xgx6>GZGe#G2vbs<6V_2k>KO||m|LOjI-f%dR?a`>9SDfmaA^5l9d^*ggK+PqbsaLRp?a$$#?gYaCp^Z^g0EC$y2v2`x8X!Q z2L6%&!A>AC4WoGQwqq%k#XQrbD_I!<;Ou#a5YrI8dBP!OA!HFG>Lez=2uEayJaMHxH9Ezes*ZDfgfo{>p3sk7ukdICTkRdwS znb+g!Heg1$7u-RPcjrr=D%!xiy3MI&lw(vb+F(%$2RIHXY;iw*VHCggb6>fKj4>e)&0JMzMp zFmPv(We&-zNBR%kF5thjJ)0~AL$3Z+j@a z<0sTDXF-zVWHp(q_RJgM*c;>`TL;zaKt8jymNR>b);9Dr0!STcgQE{L#=5tn?mbWb z3{kDo8VCveK#io7@W{nMs8j#UqFRDaE1!%}BRq&OKy*z^@BjGR$h$d|h!^I%EBG$P zZfh|9Dtthujh)00=ylctQXMBDELKY+DU?)XAGbW=?vxUJa!=7}@p=XzbG%o1CghfD zBQyXOB&C*1AkgVZ^JGU5cp86~O~VJIqQyoso}7xv&=}+uP+5ZB*baw3u&AY@P}3f# z-@3#1Ac)9dD9N`goJeCkX>zzH7e<@P!L)&F|fjiM--TmS=}X4xRcNvWa{Z z`~5aP^72~4X^#{1K-bbWmt4v8dfST=t1N$)+hi`gp3weCosVW0Crc){VzZ8%m8wncpAFMQZ%|T8NRxQ`Z7+727-*?Uz)V2(^uk9^XU~1qz4#Gux zp80gS{NDZ>_#^_z9WG{vj@-{ z-o3@V(*PmG+Vg@DB5Pe0ryuKB6~8g?L6U0gWn_2rz#%pxE4i-#fweqZR|JW4bZQwX z9Ph7r&6+#R`cC~CK%O=8+hcoJ*_ zONkITWvJ7Y6^NGb9^TCiYCYh?!4Lt59dC$0XUqBZm$du*@bm~q{_h(2PC^iq@lwBf z=tLaHC=`CC{>7(x>D&_V-alm~axTx@qVQ__o2Do>50(NuTbpEv5373Z20Dji*yg9r z@Jw?Y=_S{vLmI9p2c46qE@T>-U7>gHHeRkY$t*ZD#GJVvoB)(Exh;aiJ0{u9^lPK* zxg&l{@LjgGV>n)X<`@)T6uj@pm**JGbREJr`J+`9Y&l95L4%E;^9xT>*}FkMqW8+M zA*Fg6D2I<8W7Yt&0)7?!YNyV1y)gd12#$PJRW1XW z`vZ0lUC(4D8w@bowJ*7O_z_$N-qZ1B$Xm<{&&|g`Q*b9CA}JbGAP;Mx?m>u*0BcKF z>8o0`BNC5)MDAQEQ!8dXpT(ab?2be@o{xO{V0q-@u!I&)3QXLNkg(35Px6_F65xFA zoCOeoq*OzIiF)}!ig81r7q{+Q1J2{;-EDw8%8&UqnAK`7Wo8sy>6%@j$qHdrr{rJ6*` z74;CAm+kEcUnt)Lxrd_s;BP%2nXW!hWy!|hidh>nZRwc-v{eG#o&+RzyUJiaOtlK* z3Kd2AXXL^cwT6vF%odGa<|aj_r_`nP%k3V>)3E<^S0B?~C0V>rFbIDhXbT@rn_U8EYETiegf zrpvweaA+6v%yUoFZ~qv}6-@RqC&Br2to5iLWM((kwJ6g-E3Dlf=MtE6ykoX4FWb&= zqJeXiX^zHA(CJnzG_IoJ%gNcM%4n*?p8V{lE)<9~MS}lkivrSlx|7E!#)8d=7bPw% zGO-+FX(b^K;LgeoxM=E=IxM!m7PMN5`zCKIQO9uWdu&MZH=~E!y?W#UYlzK`-rqiQ zi#reniIPT(I0gVgFmdgV;i;Yg&BzR`EG^Kv2t)D7Ektof)N)-TW zgok{p;E|V9e2VEyfRms}@#KTmPD@Yp1<+OC-VHGR`dCo>6!c>y|NIQucJe3S)+m2Q zT<=2|sni&F&_PGwWhOz!9T8;ktuH+uD~iSaqC0+?xpzEYb8GoZ14%yi8AC*r#k@3H zTiGf`hPqvOv1}ZVKj=YJbDHLWbvyjT6t(O@91Bioxaa=z(bOFUk5`#bZIvrsd}D)I zh#DbzAN$D7UN?{*L4>13zvSIFtIYQ- zF%75b^kJ2e;{f58lvl;1MVyMF)L~71rwXLeO}$V3(YI0nOwJm;)Fm%+1?#ImGmY1O z5yPy)IazBPpG&|a8wXk3k#&!h6GI6d4{Ro)#59~>fd%t*8_9_VHUtKp)#yK`Sm*qr zShq8FBR+!}uqUH0`7;jq96HHsf-jIIoQ9s2i+D+iww}NG%LSOvfBfZ77j>`xaqvgWKJp)H%0c)HsAbBX4S?BKt=JLrPI#gS z1w;}yOl5CC*;a7`UAXhg)5DKQ4+^JQUgnVZ$MXjpMBpAhdV(3)6_VTq(h?nuGfo|w z!6r(@9vM&GSFh(IQx02g*PlLXa-(`hWT*7>!^sB&w-9`mxT3QU45KNJ`;_?N6GOp< zE)v=5yZJJc59+&Pe);Y$63;jk7g+fu0pG=Ry0);n^Tp-h39iKUV6r>LiiPkG%M8#j z;4-KzsYGsZ^HPVQwU2P{@k(Ng*HT!Sf^5{Ax8`A#1i<<7a`z%2OE6Ns=L3xNAc-0e zugKo+40OO-Pg7t8H*#|30>ClT@B<2fl0#(H!BjF3X2N2NGcJ}E0Be*Mc0z1c)#;YhN!eZ&`c#ODX1$mMTiL zq8T)#nU8)xjaerGSZ2F!euPd$CHqvKxR;b_jHzN8K?aLVB_m+sq zg?&||<{4M9-VDfjW+b>lUufkBP(UBU$nma8wf zN9%C(hUH~0=L6T1LWjON3hC>4{&D2kOCX7E?+eh@^#|QN&$DEZQ1147f~Idj@*ZG` z>%h@>iYsI#E@vmZc{I8@#Ri!TyN?$<{G4O;f?sxz5AY5>x2}kVa1!P;9-wy zeE|}_b!Y4~CRX#?udj+U{6UjJk#fT`lmc=-89rPI;2#?|5ZeEOk7I>^F@nf25UdG` z4Z}i>a7Xhm7f_q}<1c@{(D*m)1iA(PVO$*pAj7M~q%veCG4@zEw32d)RNV7FabdaB^N}a(-Yu ziZwc&ELlobKM$+r#FY;tekfzW?|Meook-U-=%>>{GQ+!JS{-?I`PO4ducEIP&m9I? z&}ypD_09*@7aFRlpu3~TXm;2dxQF7660Zhm>*v=Vh_kjHr{}f_ICW!%s;aN#O)o06 zskEXxXr!Z%-*4Xs4l?!0lHcx^SDKGN=x(c5txX#+djUa^isuPcRZm|8oh;am_Hknd z&tf8R#$^Ge@@26GUY=s%w-R@tqUTlR`%S8>GQ!0B%r+IYtAkbuEER!j06>Y0_-V}h zXm;36OaM&2cn@>?vkRmKQ~J;8lgI2JsWQ)%sg(gieT+gKfJI!oP<>Og(6LV;087xY>7JtYylcq5m zgX*crG~PPCRk!#(m&lH-WqYE>O?LF?wc?SWz+Gmi| z@7a%`=Y^~zz0O8B$(D~MyeX2|QKprc5bin7rcdS0$SHyVKv-e9KszRV0DG5J!%uvN z*27eVtGP<^qqfoK^t!F-{8z!;zky0v$Wrq6+KOTp8N@jlRB5yZv=3K}9xvd9BQV-FX{(vJ675 zR_lcJ?$eb1rv=4=XQY&mLk!p7=+D}JWtU0dybH2xn7u99#*ga-{4${7s zYsk#{uA5&M-&h`ulQ;<5B45p2m2Mhn^SzgkCiVVG%5QM|#+A?@0@3%~e*9JPjWzIhi{tkChG^2vgqB7_nY&>ys3lNx0x@f+xPhyD| z>0Ry?%c`EEj#!_>FAItV)B@u|(D@5!wv zlHfjhx;8<|7WVF7kcmFEGgB!tMWT;@yfJa`8+oR+_5|}ZVlV!I9(sb-5G$wN35>Dg z^}GlY`OBSq735&}w>}-NBylL8<&%hJkVG}s^6q!78csJFRG3R*1`bVi$|m%`g{qK_om~=5!@7jr=pQwwtw=zHUwh_YRT5oz8cMk&oa=yA*{Dx#>w4u75l! zvs0-VC+%La;`fr0XO8SRxXX3|^tU$8)@FUBBiKa+x|`h&+;etm+C%P%1@~DCM!5Tf zU!=!eyik36&KaXZ*W35wWZ9uWjkQC;-EQK&uQz|KuynDt!2R{up)prHrnVv42o zV|5R(Z~%p1+UbPXwymRNllLI1?c{o1QWiU9VhlXr84z+?_ixu}SWIQzsR!Az{wUp^ zcOt=^!tr=DQ?Prl!6ZEQ&4j_uE1}3Ipe`-x8;LGS6>(Jp;nSX3+AB&e*cWV>b;-bY3;C$6ADdv(!hidHc9>2}_$q7)O9z71|ulqzMuqdlr~dNe~! zGyjf!MVPIt%R8SNrQNIFo-(?duoPD_D>@e!6_T5)x%M6}rqkA)5JIZtLdj+k?9oVt zZVi^*(wgJ1{2VC0Gv9EhV!g`mC!;|yMD}#K5>J{qgU|5CgUO0j@&yQB41e;>A5!m9 zD0}^wR*CuhbmvFl`o-vYCNKM^P-aPKo>DtpoG@t0$9@z1G17Q1#Y2QSoK)D4b?%Pn zw|1l!ddj(S$2+Jb50QfK2T^QIE~(Wnj=wwwU7Tpp4++>EnB60o(VYg%v2+wq6~`?; z5;?)4D|tx~xAXd;HO|(WRhh{1RhWFU+qTAYQZC`UcCR3>6-WDsG z^>@h>LCtS`=%gp~lK2zDw?~gcH&SqwbiKNh^LXtpSGwc+Vg+%^jWxpW z`a30yBPw}yg9eoA;zQGJv2^x!hR>T2d{FKV`tprAz6OX4v-;=Br>Pe;DWY?EuW@|% zq?tsil0NAz!CyJ^=eC7C-{_Uv4u*fPDD{U^wW~U!1A({}*Fl9Trvl zwJS(>3P^(j0@4f!Qj$t3N=ZtMNP~1qcZqaKt90iuba!|6&_fO}XY;=P&N<(?&Nbr-fqq)Rt&M5>(Vd~0Wo)dtB6)PLXUBB}mMA*Yu1$Bu#2b_Ur(+-uHrRb83+ z>UU!2h0im*n9>bbcNOEEu6Z#n*P_V5)CV?=p>cl^V50>g?a}sz=yz}D>zk=(s@{g+ zd1qoj;2Qd~2&SF`>GPwzTXwT!{O&zDiL)54l?5}aO*yT~U>hnRxr+A<8zw7(CdP6Z zg-jai@=&Qir5_^j(bp=N0J5j@qVg3QC-&cN7Db?#{x|%81KNJ&{>^z_FC<|3Q~D_D zB(hnyKVfMMLp!t3T=C;S;8|H{?dbdTG-c*7=HqbsnJHQH3KT~}UrF6$&@XKIjefkL z#9(~Pj-k|w#JLEA4XrN^QtXK&^mT=8x7qM$_|hE&N&Q791yuI5_U4^&^9ECg+8f*%ut_}$52jvErH@5Ont)$w zkV~1s&LPXEN$_Hp@F^ZG22m*b>R~xd(yCYsojHH#BbFjk>*133MLYJRUqXd-hysmo)g% zbN0O%XDmbo3R1YVTpeD2vna5>}FSc=<)m!fBdWf~4a2 zKMH;;OybA-!5M4vIfEMrcy@XbKh^S;I=!Jl*Hxy+(Dts3We2cMgK`(#JKt`X0BcW_ z^Vs1XM2KV`qt`*eYN_I50$|%}Gn-TKyjnNDOvS5c0j9pw_M^r8xsYpdTX+Jjq0(_L z4HujD(AVx$>m+J3sBcY22- zxw#hhMTQ%}X)-Lqm3^ZBet3IzJh!Ju;pD`ozr`B+D>V&fm z#FcnvIXVB-!*efqku&d6Y{^;%02dqpT$JHvMUZn0g65Z8$T_5PzCb?|9rpR11ziRL z;1L(`Ohb}feZr~R`9oeiVbnULk^D>k@YQ0BFn0e11`263dq6Yqy+Gw9$r{NvA-@ocx~p3 zE`epP*Vy^DnF1bCdYp%Lz;G6}=|tWPFv`vGb;uSCDi?xV$mz z;5R`FWT09GdB7J5PuvS_vwHW71L>gR+ZotHmdk7OEZGR0L|48yKf0}b6;fL+=j#-Y zmPe!&l5WJr6=u#ly~>R`%K7_FT`sp@^B6PJ*;ao(;a^9vQA<3gDScO@f-C-6YmT+- zZNE(L!!4Gm9l{u9`M{JK>$WPGP^R$|itg8$2-Ep?bTF~JPoPUPCtA$(mMTvRH=^l6 z--ty#xEpreM_+&!^M~`AfCjx`=9|-=b7DY+(Z*B@4&Y$MoK3siqCqaQD1TQ7YJU%% zP(P2w2inCtcF%b1dUY==wNQTDvFtA_Y#J@-n61mr#lXfr zwsg~~ycKqlmPrg*oAZx2_b!3Uf0|q-6fbDn=1AzFw|f;3C%1&M8Tg325(E=1i$0<= z%Rc(C8DSxH5LKa59RwW%YEGN6GRw|LfOEi`g8g*ti2d|C1W^XNBcYLX+mxfvO0G@?NyLvj}00IL#ymwaLK5Vf299HTkoR zDYtP}gR$?}Om?V#){wvx_m~i4#7?nYyO>fLlhV8{ys9?I1+^P3hJW)0N6|~iG&zoL zDC}WS!}7|k;h0V}Oo1LpH>ewuLK?zd3zcsk~>&^jO)-F)N$YA&-( zUPXH$xoH44?fipHw`#f-b9F-H4)i-wLnB{l`;7n;ZFi4jdEOv7TlxEP-J(ykFd(;Y zvKCl|hY`M4^{@XyiA&xP3wMw7u-Ict^q3Y8n}1NN@ErJekH^-_9$q@&GaHoA?k(9R zF^qC4_K&`Us3-4TCg7 zV7ShcU!SI*=J>%q9C4~2MEKs`L*1-rUNH#=u2Z~*9sdO76P3KGqp6L(8C}rl#Y^zQ zl>SYV_pRx(%LDHXRFGMLC|g@#iPr3X*KAD}d@CZQ#>J8iV5r4RqPJ7(Gf^6a0P^0d zRf(JVfEgKG5|qPz!wggQAWuYiONbMookI7ITYgxBUh1w-?u!I z)Z%)Zf^WiQ@kZH#KhyzG7BZJfN&OvAnM!pbPR!vc!eL!w765s~E9-j{K9vlhFKK)x z-M`QH>L@Z0s%^=pl|c@SCxEw%u@jdv{KYcPx9^Any-nsm=>Z6ku#Y6fno;VBqahQK z5n6o7M@&GQ@ZrAiB5*dRIF8oixJv;j|4qFKI>oz*LXCGiv_R)jAOAoI)gB?8cxQPL z{>Vg2M3lWrph5D)h7)fz?vn9v>9KA&0}Zg{Z8X0BpUl4RY`v`~>W?JbmYdgi;EXS+ ze;kip7{D+v*6u$1nT-xRGgGGO#H7t?J_z~~aapXAB0Q~Z=zO`2y*=+4Z9$Z8Xz{Xo zSDjt5M>T94EruNWY^Z|6NRGJd2ZvrNE?#@JL}RbkYE$MV9GyBRgn#UD070Uw*>xo3 zC%KIErMqZG-J=Sh(}P7|&&hVBNPL)jfbW$(ug@QGSb}Xc=NI9=S`8wq^pNVesqBwv zcnl7=dhh4uw4P2H6an85CsMZt+g8r;X3!WKkInS%t)Stwu(0j&FWBX~9GyQV#B`GK z+4){D`_pXlB!-jbmTV&NS1us7?Xz#6i2ZqRm||waXTn^}1njhgYXw~w%XVHpV~UDbQ`1OZfKIrq)yu8RX3Bw!76k(0I{07x`G9AQigPe zpmy0Rbw6hz9j5am^8QkRgKI~1r!tfT9Y32B`SO{N?vw!J^pURiUSMdctdE#G_5ziv zVs5v~AOQ5tho@}U9ItlyNM7lI%1YGO#HWRmQBi_JA$A>SG_}deU`_r~Wea0YO zsc^~>MpV%ZbO5{NQ091k;V{|xKI~sF9w2z_c_R23z%tz~$_}FKfQP^A7^*;X9LGO! znL3=SJz;^-Psf7l=^|Ux50MaqR53?kC@WLEz0`V%qGt0}2Dx$8rb6jq^CuosnLvbC zcC{Z6@BgJ&?6&}^1rn)VNQ^M@i-e-?#l_a=&f7SvKC~ENLuWvKD|YYN;n!xdCzZ?4<`mkT^3}qSS#)Y%5b<31&+h1$S6T)_8JNfoWx;@7=IrmSETP*t~7kG^N zO*EBI_svIh{1H_J&F+@3-nHnBQZ>ZiI8A0~ zH|ys3=V&XdHSlm{sEiSSU~KA%%frrrxlhyGJ(hf%OdhQ**tvey^6mt6 zw4fq}LJyy3u1Xpz&iXZFLA@`{^diuVjZ%T3SLfshHf=k3b>$%CSFdh&7V*6NLGlCv zjkrCH$OR>y@MrJ#p9hV9K;5EgKnX#+uGH7bY2~%?bsOVkXR+S(%0-;Ti;E%g=Xfzm zrR+9~sUCsv7#k&92)(%2o?HscgQmTYc!p^Ftw4rSfc?sT?T-Pcik1;eg+XE>ag^Qe zrIbfA2VK9ftatN#0JN>fAR*AEiG9t<15R;E0Dp9cLf*vn5PAJapiu8Z=;zUwvsvXv zXx1;X1n$0s^;-=rCfTL7p#wjG-=AQSVmFYogCi8ZWxe=M1N4u8oZ1p;!dZ33`+${H z21km4Ahhq+j-b{ZDQ>w`mjEYj1*_g_Tj^wnxCIiRguql+&E`}EOs{R5)_$A~Q{BVSI^hP{B)Mn^u|Qs~4w(3)l03-o8>qJ0g^^aX?n-VE58YcyBJds34Fi z0bAOhMM=4X4|}RmBLpdqNiAxZx;haF1TDJ#dCvzjfqTh&$z5#0r(eDJ&*vmB^&W-q zHTC+&Y;%|YTs909b0=(8kB@sHT`v&L>~5y_$f_`ms`L0U3Ho^m>C9C$F^bS@xvie6E}2 z+qCl$R(m)dt$1%zoB_3b1WAWudyA9jng~w-Il0t2F$m=~D+mSqyy!R^QCH0ITeS%T zIGwA_cl3XRHm5vhd+c~DR3UQvSIw19MUN#X`>9-{+s7&x%B5j)(J$V+>8W-V5=*Gt zv|2G^IQs#!G)Atzk3^dWkGIBRGfCg3zv}~(n%_mN#=nc08^CyRhfM%G>gyp;wDQyy zTBM$-iz4$2=x~gccqz|Mmtd*G5-c!DaWQXDwj~6pNj99I1yF+!&L)fnSln1$q2>>hC17vYGVq^Pw3>m-c}> z(L3lL2#q+ibw79oD(lHIjXrLx9R98MUNg>cGZ^z3sZ9NYn+7IW0z1HI{{hwr&Vlsb z1)aUVX}PhrN!oZMGq{-{i6-*bu9PKfelZ2y+Fxdp&Wt%JrfzD}UpTnk^?P2V``NCH zlHc_^yj@axDVmW#EsVIHV=7`ODfN1*PC zx2fI$!rcQ117B&s^@N5;yjHjV-r+5~r*rwqgCb)oj$Qjll;DxGlM%F|AXo~x{Illw zCR{SC3P}M)8aSif@(s_8UqmbCH9F4GHRH8AAI|%E59)ne=ghWHc|_eC|1=v$^|G4$ z-;6Fk&2Az5X-D8X;0u%3uclJ8s?$p72=qPECdOv!U{x)VY5t$an>^Xve{oRqUe$W= zuen<7@F|e#ky7#*q254DDM+PE{Wc@Ko!${wP~Z^bU<}jq9Iq!;P`J>NrKt1aX*?GH z!e^L=!T8f&uv0@O`XOeM^XG|RLZ{{vK;LWy$}FxEFUI7Kri9Mq1-}J8)TXZ4!xOTZ z5B#@>9H-t%y`N{&-!!5xfi)jck$icJ!wSFG-Z|WA=q~>nI1g}QY;1Py$GEz6HmLVU z5uRfP>cj_rfZT@CdBMsQKaN%c!$}e`BDydA30oX~O3~{^(z4u-4=A&yahLWpR545bX7(Z`9$vRq*y~@M0rH9&)Ju_a0tmM!K7TZyeJYqbxM=>eMeO1 zG2tdWxR zMG>|vk}ZYqtL|d1^ACnYhe~@45&x!Vq%xtLY(jgnH|k@@!lU*}J+*mDnBFqUcpNYH?=T>_A&MkO@bPPM}>&-z%LAmOC`pD9vH zGgU9DiJ0945?&-0+vsBEmS!;plTqz)sIw6o#B=<1Pk4J6i*?WJ_!_<24p~&xe5nXl zJECx}329oGn%!%xX_FfcWQQN^z66GU4T5Ko%YKCO7`xp1^=i&hzKyopHJ^YU1ks2R z3x0(_5k(t7>+%}v79E3nFZwf(EU}XzEVO`uk{5E_6T9N0^cmSJ;&a*_&x0!+Y{&|y zl$%IoRMN!>&hZp;tSwP@z z#BTrK)BEA$4r+|>xVi)(l0#5&6Xar^_hOs|%jrGg&O zGvnX;ent!Ie-*E1;;w+lZSp@(1;OX+_sH=d(F>bt$&LOeZdc76@h|}zk56vjbn{+P zm=EDa2mT%{_1T-&kq~%qee5c$U%Mr9eteuABq_Baj`=Bf1% zAKMeVIBcKB^9B)ci<;IY%sw7JegN<0%$xsV_Eok>gD< zwGz7Y*~-lR9UBJZ^H5S&KYfW!d(-d6SwIF$nuwTT>~O!=%kRsDsX1ugs*$u3&!dku z*F&b(X3EV*XQb2em54%OLn>k8Q5CJ07`cj%)-HsF%X|_aVByYH{^~j~*5}7}j0YCr zeU5XTd&(+h@)Ow<6u>aLyND$r|G(AAnjXo7TDTmioBgADuj5LsQ^h-OB{)GY;Y;t@ z-0WifxzS>LoNU&M7*3{--}9JmqBdKmmgv9r9%ODY@Fni+vEd4bevxpP$ld85rr^rm1hcO7-%Yh$zfanP z-qwHM)g(1q)es2g{N+Qm1T<~A8Lj!YXzaCncT{{z#j`&xP5ur<7D3uSTu ze-uOUe`7NhY1NC&K{?Wmq+2cvgMrZ``jT@p&8gp@;jF;WQ=WVojsLBG*Ga)uM5Lm-9}kyV884<+ixa4| zN`0+G%Vr<}mqOh3F)Wv=C;!49#ad*sn5ZWTFwjpt`>j@0dCEz< zSo8tei!^^QfSj{0546UH2x%Et0anau11IH-Cm`h%-N<(G(=>~Gu_e@07nM51aQq{g ziCU*8UdtDO&vj=tlW}i~u>5BCPEVV`sv9k4^&?4Chp-fuewTptNC+X*aA=3$4x+OM z{8^LeS$ic=rbG95cg|l^gL5VxA_;`d`xcCBGukUb*DoL}h(cx~QJU$q1@9xQn<_hM zuz4ya)3_@jiC|gmBL=?tu|(jS9S4(hhycw{w1|r@n1C^9L;Y1+t`Ja0+o%0=5k4!v z36%FGk)9V-45MQZVz0<7?vw?2#M-}gv-^7of$EgLkSj-UJ6P&I-Rl6)I^@*=FKQGz z(I7IP*phwp8%PviEqs)y`-1`0%z@;BXn$F7^rsiCW0@}?zDaH!_|<;XyxtSlDoOEp z7Tk^<@n_02jkesmW-?kt-ComxjH9KOIBE!ZWh_v!zm0U~2>uGl%^LAeYi83y9S+PD zlsUD7yzY6CO|`+`^jS(v9=kL0zNyN)YYtMGFRWs(4gzr3S7IxT`k6g0kC1}RlZC=C zc0^BLD8uL)E5G0ON&WuTt zPqT`9V=b3abUHxd4l1O@Kqi{^n%J=e$=nvVu5bLl+ez(4Eit6-ElHp6{>QQ6dpptb zt-M_3W9o8hzteUSsxK6(WsG+Crh+@4e}*%XbOF6AQoi~j-vs}fU_U8`y$QJ=SpIJ! zK~zh{#EW&eyPC_v$wfTfHwi&DwjwJ58QL)80Wj?IPixfKB@zm<7IXyCdVFrA@l{5> zJ!tx1qBJJfMLPq9+0nGM$+eFwjaEp;T?ubZqZ2Kr5d!#_8sY+SSAb!mC6RPuh*0cd z&Ly+O)}_lk^}^9*a`$GAqA*L1LVe^Pi$lf|ufoY~^}cE`{eg7o`UKDlQ0on0+5g&9 zwR_vTZyC>@b~~8XFt49)rvrS7*E^qM$}-E?Z%KKru6g$+-$FoANb5nwg(9d{!40ju;C&5Bs(SV&?M&Ta znT}oooSGC_=Mli{m0!la>R2%2yJgA=_DdKDy&dgD{hYc1aX)|tmD9?_`=Y1UwDTGD zlX=}x3)xVxOcng1SK8CXyg0c`on~qrcio=v3NbDDBP0w(Q}7=cMazRc`)iRzjMQvj=N;w9vSk{ zWK06ujrk+dOBprp@#`n8I<>ZpP&&SJ?x3jj{;L&FTCe=7J_Npw3za^mdBWSR9vP2D zgU7Deat#+WE`lzXmzwGpf?Lo9W7d8b$FMDoI*E`Wgw&?HMpHCv_u)lr=o4WUjgmzzt&17sr2# zTnwC`#Neokb{JEEtS-_#<4|j&i*M#1U|Bg{bxu{T{}dwEY2QO%QX)0eE-Qir&h_!q z6~=(b_MQG82wk4&D1mVS@c zYK6m1QPNA#^xqQV&TS_STio@%fJp}{1AoPtCWBo2IbZz83@Qh&jrsah%0fZdNg{k*us3mk=?$FBk8En^l18OE82okC zed3=gyquTDZKCoo#2>q`!JGL|sNyAkhJ@8Zlg?B)Iap6tVrIJ0l^@D7Th%8PU$P*p zdaI^GF||KlQ{UCH#nycZv=lV%NCw+1yOMZ!9XFa+O@CsBcO6!48_#OhtM7>tO;bf_ zwlf@G=vGhH4LzFLxOef8`T-37`~{Z#*1^LoXAMyx%@YXj!JAhlc-9P^rOV z+FqZDC<~3}J)_y7+tupR8?7AfLEn7=~)ocSY^B@u7CwUM+_v`i#-@%M>FV9;PHYf|izwX;Y*Tgo{)A4QUZ; ztg6!2gSU+LCWK6N=7ccLvGnerX8pDPk$YV+;49p5yqID?r1J*gY~o~A0|x^e(1+7a z#_FKM_h$HB0fZ%jYq$W3760jkXuME^7_jaJC(I=+3$Ipsn9sV3h zWKKfUAyWNB2VLouv^DeLvE5WJl+$*uDN8S>~e9ZhtJkH;YC9AUEa2Xrc_A`dYM zXnafyCR-rxgqK%#k3}WqE}cP!1@Mf|tkDJ?dxhnAG1E{C0$R*Dr#(}uuf~#4{rv^L zoz-KVw57k}mWEC5cQZ%ZTX4n#d?A=KT6sqMt*9+;fpUm7FbFDU*0{sb&YDw~M`*l6 zFMy(fPi7KK#RT8wm%(5bWhT`Q?56V!YHPX;y1Eb;X+WBm%X#;6hAIN?F0J!X+u<5u zza3X5rkb8X8;x6yRGr&>=Op^*R{DmDipMF1b2+s0jdm%fFD-`n(x0w$IGLeXn~Z|< zhjg(N6N<2B@nS@s_Wiv4I!hh2<(yO;piN0HoOwC*>q&YOo}oy5xcOdz2Oy5|Qdz}- z3|VvgvuF{=FTt0G7vtL(xG5nBz(ScyRnD*T3Zlw%f2auMxwbP{&2*Li`|fD*A_DsK zCHAS$trhYFJ4;DvLQ5MPnS*0Mv7X?k+1fK$m--h-Q+m3fYhuBZac#F)Mm1fEfL*cd z0@5<_Miw(v@pP$|Rv&LKv~*PGuZ=p70Y+*brVCrG$H4FW$M4hBOJshri1k9}-?U{O zEE-nAFY|cmed@!?e~FG&;JrU_6S{GUC*-u3$n}F;zv&x5DUSA^gpj^skAGJG+V64k ziD9DL7foX8Ni^>3^=(1vdaY5Uu`^UiyBk?`eF@^)z)8EV{g^@&paE2-Dp6-Zh z;{))?R}m@|y65`PttQCi5aNZwDx3kerAn?LxJfJ$rmN62C?BupUL8xD74!+G_xkzV zzQ~xR67V6kWWYej;I~@C*@}t^*Iw-UU4M`#I9}&nDuD_Ow`w%W3kZ!1;jE}IycmG_ zl*TfSa#6R8?oDvsaq!6`cQifpNjnyn#Z!xC96j&^bp$?mX?pKQx}>720c>*wfRA@l zZwzy;DlZ=okh6ihQ!~&N$E9c`QAtXT(+QUS!KgNe`#BA(8~akxOb(cX{o)xrDM*oDAHZWpi2JrPfvO0 z>Uk~97|gQ14-EEV7$150c72Jj+S;oNOO0^CaO71Kv+rv9r6;r0&R59#h_@j{TSK`( zn@`p(NU|HS@8&N1l?aFZ+8+8S3fOAx;N<6``%Fz++t~yCPhd444ZO84K+;e6z51Q7(XH5vXw75bD{nml}}N5tDzO z%nvA$GRU{CXFnK8z`OEhF8J0?Y0nlpfRw-1Vk z7u=a|Xo?P)Z;xLjS08E@xu-Dx<6;ANLJFgrNmzM3YiqgOfGD6$0;}o-B)y)M%W(-A z`LP3cEVMPA11fAai-}3x|1L1yx=rrE0-eK5YtFKvu)9AH1Hwrd3$UD0#Vv@p0%wGZ z;sLW<*Pd0N0xPhh5wyUUlJk$)_@iT>{o=z@j2Ed34y#uqoDE!epifkjBV2&Un7~;T zF5`g!x-LG#3&2AeP!ab*F?Snii?J|lr-GtxSI5pt{Un=Qm5NCn@suw9jc0*74Y9NP z&81^tHxP*pa+Mz$H;+{ zgCx=83p#Iim0O3&Gf<0D(atkz!1_l#kJntmSq!My4D!OcZTpkxl+dm~O-T-M5LxkV|P*-6(HA*vJ`j!O7hr?t)S(|K3eLY_fq zEJ?7yl7>~3fgi`>aCuX_h!9z_4Tck;;3zC(jxAI^m5^B)ooNelD>2pkfhf}DM~wc` zD|9BLz$eZv=Q--h;r-7KX0;!&>yni*Z`oyD$-Q$Qb2|!(am&tdu=YHenL4n@xVtlF z8@PJ)&~pJuDptyWeBPp|fm3o3{We2*%l+~mtct!f*uO!pT5`|BbaLR6u2#yweH3mN z><9ZUC_Gm0ynoUMS}3S_WBS?D-njN0I(f}Sdd{Cm+T}Qaaxs}E43|q2VbqYw<8<$m z0oN{1F}OZQZVrrki$#!)H$;_>U_zcnEN{jCWO__auw#j)*VQ#xvf)3Rjaa4o5%atVE zd1pm}MTwFg4^FLP$*`#>Y+Wb%}Ng03T-E|gNqu}T8 zT#REI_vjUbb<}n6+UC}K(R^*e>y3xak8#NyxHA((eAEv7R&h)5iEoMG``yF)_duAk zsBEt+pdIVdmh{>Y1xO#;s_nL&W;+s~UyD!Fn&ZaI#>fZP%pX^O(go;VF!+s4g_7 z>=k%~f={>q?2}XYl0t^3yr16Dp+B6;w$t3@z;=IuK03+LI3-3c3i2#B7~sFiBV z`TdsYp~P90+CUm(uAYS)jtt8_AcbZ2tAH+~TzxB<&5IZh~vjkINb+)R;wZ zq8(Z*?&XG;J@k~hkxY?D@&O7OaN|Si^BH3O8h$untycTi=U4GLRn=3G?2l=K^4XI4 z)(=hFI-gg=&~et|D$PgRMZ!g`OE?J^3+s%=J4<3|JuwO3m)x=Pl&;N|q zeYdG5Y5{B`Vbr9ocPH-JtCGO3{_6Z-#wJP|{1rC;syCrwp3A|j5rNP-SwxD*Rql+w zInD~m-Havdnb3?QCvEy3IMASw-dJa{`U^$H;rjC(EGFNgCK{J7Cn1SDia^UroV8W^ zOU7vl}7-XqA4wsXu?r)D?w%p2VleK=Fv1 zeREE0VaLZ)L=hO~mAZL8@*=7d(CM#ooTotFpX+E`Z8l_>^!uCJUl$3z84Dc3C|pae zATQ?PNShPF)pBZLaoV4Kx|#RT0q-i}^}#pmC!M1+-y9CMPg9fD(q_snF7(YOG7~(# zPE#8yKfIo)vWP0ws~M^O?WIco8{WTWeQmo{G}kQ849v12gUf%ay8?Eo?P1Npo8#Y_ z-?%+#A-j-2VwOBur>8V#z~wF&#Rr0)xrldARPuf0oqjjOA68G?YO3=k>BrOW&1bODX1Q~%8%c`T=PIT|;?i-n)stPWiCF`9Yd(fvt$=#|(Ph({4f zZcG}jmn=%P<2Ur~x}g-@T)>7h1X^op7ZTsK9X97&2a!DhNh>W0c;R3Y%Xr&>aYJuy z{Vf3)s6BIzK)&h04SSvMq`dz%$6@lgMDrTEE`N8w+Ed_e80oBJ_yL%c`$_+T4}+$) zIISU9JzsoM#k-4}%Qe$-pu!caTJlx$l^(ZxBe$ zq#gKCz62$?dY1(uv|7fD===i2x2HD)qc4OV_zOI)_iHu}M`tz`-47kjy4=1-ijBL@ z*mP5BSMRAdL^e(Jqze{YU!2=-aK#qWCS%@MG3DMx((`&x2^yR~(H=Oac>Yl!K9isM z`-ad`3Un$m!z^WY3lBiKSVx%9%*7kGh>}BoNQP+6I5Oz;P#WRPbbB3rm&P_v)MLL1 zgRkErJz3lc&bQ~;=UMh{e(e6j1UI!SEAe#PEvO;AsI0NTNr@M7&(56Z{ok2v4W@nP z(By(QP~Fj?ZXxv!m&PZ={*5iRKy2CMSEx!8v5NP&nVAyV^@^`Iog)y{JBv)om4ZBW zn!k$qt{Xcy%8TPnr<#oT<8im)d=8)EOVGExi~p{Dr&Tt4hp$=^#S%%!P-oxip+eF# zGZU3T2V5fVBS1UZl3;P&=HnU*Y%y-qS$$`+9WfP%9BtuY_;2p%q3@NDC5ffssW+Yj z5=rmE@(@o)7)*X9wR%|Fb6}wm{U^@n0#*4 zW@f$SEx+h`D4oQA=sBnVa4I|StXwgY9o3;L_cJgj}Ko zr6Ba)hykwp{MmiA!x`4~Qfw3PsT|{W$(*|uYs3!aJF9h zz^<#uWyCP*0V_DA6`u7cEEZt&XK6`!$vqZ>8Z(>OuC?nHV{Ls4FR5bjKWn;@yeRp$ zbSAI-^C|}OU~*!C5y)CWMiUpxc>2>0j>dl|L)?K5Hbi? zX18VgtatmE8&j8i_iSKo6FE=akK}HVepAZZ?92@#QTi&{ftGVpZ$&`gnibp?;G_33V({-yd#92vnu z^m`6ok#;^LDx4t&Tz#b1;&TmF;Fnb%ATlnZB(1&(>YCof*JG$nlB&?!LX8M{)Yj-o zhd1?;coe}(g{EKb{vs1_u{~90U_Ro7pJZk7tP_bH4BaB8@$l4 zBz{Z{J|(3kwOBnPk4BhG8!V*;x@CU@%%@>_>(+gjL9`yE@vY=g z1?{F_(YN1UipamNJyz>GQ`RMTtvC3BO8adavD^D9eP_5R-3;9k#6gpnGSxcn{<5J~%-YXk`FtM$*gMlQLxAn#l_JfDv< zihD1u+sLlaI)>a09tfs)gg#n*EWoE;&b5Jrcc)^z+O!|Kxb*pZX#|?O^esRAIPoFq z(t{w-qEx>%k1!b;FpJC&C6BzMdOC>hp!^v&etH#{u84ihDfS)wr95n%D8sZ7iCywz z7z(i~qFVe81e>|kfu}b`+m^fKR%kb@%Lxow28b0XIGB#{-?;K^2`vklh$NY_H24JJ z_fM#KfZD?zo$AwVvQJ4Z{hv$aKXmCI&h-DdQ2?Pp=Z6myyq-{VQos63ugExvil&~U zF}>e=*5mV^55*x0UVr(Qfc-z-?7u#$*7VK5diz3ALhX)!keKOjOjJYv=h#iuGF&I+ z{~oCUE>ZC5*_ia!f9Ht*!vRf*kNWU$y>{fwf0h&9vqIpY6h{6=T-l6x8k+kU44fU{ zxM}|Dk^TQa=D!|yr~Gn%5`VeThQW7MRqJOTc)UF{GVxK1fj0O2^$SyuoUc1--=AAN za&B6Z2U#t$1M?DM`;?$mM3M~Ul9l>3M8V-VjpbxM9~f;<)?e>TJN`5oh?m7U-A(*u ztlwl5r{wAy|Dmqv`^&H1RWer0qi>McM-Eq?j!CpDocv4%lGS_l^*a3GH{iB5>nqIirrp8E)v9sq`WzF7O>O)1%v%PMZGN!^ zUIR|+A@T1+lZpAq-kNA^-oOFLPP2DJ}FAW8N#4q2U>xrM_#iH~Ep@X-v2PP!p zD))8U!lvrWF)e}VJn0TtNzCAWN?qUJM0e9I=6W3q?cTvbEyP~Z5UzXXbL&rW>9}LR zBg(URH-m6YkH0>IjDhqUth2wmG-Wgx#bQ+D%<9$Djd{@?-wgu8RkZazUBe9;-av_t z0{&eQryV=etVF_4R4)P>~M7nq@KZ~psx)>1g{PVSV+ z+3uOzZ=(R0posYhKHmqZU}c6TpYAeJ{g@JH7`A~0xHDp#`3iSk)Z$iTih9v|`KN&O zapQVlf=(xNSVF&HOHf!}N#HMz{&!H49_w-=&`&*?RB-y8#PG_Oc%Di(JIuQ`ZDz z;If9(vArkIKJ;^Z4u;ra+kdmMip znLGH9M7i;nHK|NL8$y|Jab>+Hw%mP4yeD2T4Esr^?zpfzRT@qVfNvEo9RMW0E>3;X zSTJW-RPNG!GiEx=GS6eZ%26${E=~9$Hd$4C9V7}Q6XO=sgBp%BVvRLq?1@WUDg1|G zuCTNK`!+|-ka))n0%keYcz}l}(|KOfx$Z9EQnNDTsMF;q*+`G9IR*lV@uXxZiF-=D zR!tLvk)SKBFN;+NhKQDzbvQ59z;f+^xK>-(2WEr)_v59e4_=-A^l7 z!&HWXl5L%ijbu?@E!A5dHr+ZciCssQN}YI#88?}~HV~CQdp|YeGqp^K>Gd}d{@)hq z|8d_pB>LYqiv)+$b;>tW2aoqgwOlxMfvGVGY2$IZx*3xA?wm8edQ2)7gV2~_6;Jjo zS#=pkXXXGt_(b(Um-tY~aTc+03?x$av+Ilkhs{7ljQJaa*SF$wv2t*H-ufuuPYMXc zJ%XFqc{hxjB z{m#^qm;TMcD?aokDanQhYyC1uap?{wr_iF0CUx>hZwmoluI4q2GoR4UI3acGu8z&AidKuv3 z@$z8td^d!*MAy`4`r>GsYc zwNX9ONK&K89xE=pdt#yeS{I!xaWS{XoE#Q<<3!IYD9-O%SUEm|hJdO){HrfY^1S^u+#^+4$?EP@P6S^M;cR<{|Af@%;L`36x8Z<^XiQ)G+o4@y@Xf zv3jw_9l_Hr%`}laiFV%Q_dg7wL^$A8RAN5?(koI5iHA-h68QqWqZJWJ=-9_L_`;9- zSIv7_*7TeGr!9!Yb}3TM z$Z{MHi1HExp^03lVUp?6_tK^+8vz_PeE4BYdh4*)Qn@gaKr24TI%WQ)1oV8!FP2Fl za;_qgYW#vc8D7U>eR$HBovvxSBjh+9!goOf4u9#~cd6sruFOpR1syZ}!K^}C@7%-V zqjrT|cYj0M10@3sd@4*1hp(6rlwz&do=CSz>x+FU80csgI-|o_)>zw!XjNdd^RYiX z$h{i4cTaF;0{rUuPR{Y6z0j>%zz^iVM)qe&@(^;}-;5cZ6_uy^`{}W_-S7OxZlTAs zr-&brGZJ1pBq<&zpEmT9)Mcu%DGwS}+Zh`v)y1|}cMTQ}HE7!>9Pka=tvUs7+Jc$v z5#c!4F>A&3;+A!(uM%(9G(XHedHo~1%<@8b9O~2vT&x6*rbp(aMq$7c5aW~02AVAA zf?>20fs_t&liE4RFsJo!48BWwR;zJJ@O`9Y9FutJyAz8U2OZFQ`>`_q=s1DdSy?)T z*CKce!!0QPQr!&oFtWD#{iMzXLwg*VTfu>kQNg)grTgi3Fs9C5a-rLOkx+{Mv(46& z61mPacT@LNZP=gX+@RMi~TpwN?e(n_fJeT}w_KFX@ZuxU*QMUX-DIIcjw zUb)P$ofK_t^q%%`lD6)q#>IYMu@p(hMw%J|y|R6&O|IioVdMMIN&o#*p+^wrR z$q@VLekFYACk5$ScgQ2YjNcJ79nF$XpeORG65Y&ogbukK-i1I=yM31{aP2ZRYdSMT zmXtTo-vyjw=l`IFLbCK}OpB-BzSMoTFSaft!1Nag}A2*fsTNAVc@Q z#A~amDuD^dRWrzQTVok&_3GDc8yqjLcwOYxoz^XGDuV09tap9`GG(tj->^SSUZ)Fa zm<_u>t=oafyvt+FBkt(%YCbxlDCUvW8uAm-SBPP)-3fi1XnHg&tS@vsVUlA5xRg>J zO1xLQTwHNu{PQt7SHxJ_iMp?ru9V7#(HbDLST0*WA(_#+4{{M?2omQcgZo&Eo1!C$ z{#`=&SN}6hc3lP@FXyJxieZYH67NRE*)3?<@ui}tONIIV{2nl7L+`og+}+}+DG=~I z5IcIMxWOdb$19T2sRl4t@=W?|n00N^jl4?)E_)jouNXQLs37*Hql%nPM8+{xl$g0k zwIK=2QXt#T4n6CO1H=A9@B6s5pq#secy)bf7$`iF?I+gT{@j{%lri)A-N#hqgH=A~ zAT)VD^`gDiQ5R4J9rdUN)_e5vI<7nym5z7o_3=k`FcUp++bq#-fXrwCvRs<);Miw( zXb$7OChJzxEvB2}wJyf-rL3M;TFK+misL0jF7GY7Y~!mC+ZAuuqBUlW*RQ zZd{^iQ?X*6Odauc=Ik)S`VK#PYDvcKAsX$K5=PKswwqbgse?N4ujcc=|M-8`9bam| zVaybwzme*L{CF>ZH8?>kvoT#Hq()@B&FAQSUA8*y&Mp6=fY?{e>Mph^x#!seV5P$( z=9@Q&VT?gZG=U8#O&fv1k#)}H;Wkbdn7Z%f6aT7~q4%gKTR^O-gtiNpq;^8>dRkGcm)h`c8nO~>I z$p#iJCh)OZO;Z{$GSc%TTVWej+pJcoWj$CNUHr+Ge_|L$xI+^|Sf`T(H@UmOgc?FAF zZdo$l8*?->LOOjTv8OK6R>)*xTkVLwB82A*-KjYNV_HRNmG>+I+7R58bd;Q1_jvBJ zcgtlxXKfU#!%3QzXCzLGbiW+ez0IRK>I|FG7r6NtN?Ub8c*Dg8K5^>ZHXWVC?IJ0j z3ss|e0UoXuF-%#UY3N`R5DPYwPFQBA^4JOuWQv?VVWfQSRBx$>C+m)=3LC$(*8z0C z-+$9#D{Ay?&Oa!2R@ugUB&TZ9p_P8~Gz{@QpknrBuKEgT@_u~P)`B4;vCL>}mr5o) zAKerQF$t(?oZ(=zU;NM?AvN3^yKU5b%91&e1X07%a-5wdF)=_P;TYzwjMpno^L3C* z6v&tp3*IB?LGQca{S@oN$l4>sFgeGxel4UPzc1tW1RM6I{h7=*q4En=;sY5k>1}9A zIR@`?BpZ00n~0l+l;#6ys8us`8ndKU+nG-b>Wg-(+ttAQ3zJcr@KiJ_JF{C$wdzX| zdV^`F*{5ndOLzd4OS#7qMfl>wDz;rFCnsRXi zC;T4KMiM>!@iIP&Qg6|zV9&kYpwa0_9Z#)I^ATR&eSVf)-OK7wuoaanX^5Y^xCx<7 z^1twqy}yx}@@)T2a(Q@_SMp}0K<%rg7%DZhl_u5e8nzp(uFgbkZP`aseA?xuuqwAD zW%(ur#jk4H?!8UBOL;7gwy`xTwL{-=I0E$}scrX$N1sRG(<;>|b5>dWWUv#i5TCb` z;$)Awi!Qi1U9Q5*s@v4taI9>~eG;lQGd0#orp_auFS^=Sq(s(F6WBA$a|t4TTaIr1 z)EP|@tE;cwdo(#}n4pC@I9RjWt$hWM#_UjZz-Cg#OwpfWJ@iYzgK{?jm9zkUx z)U%?X{h@M`h*r5h0f;cxis%_3)9&f|f!3RDD#3q5>*q^8PJBURq4K|QbA54+n;hs! z;l!UQ+SgbEYQDt1u&bL2_soBlzNjTx*=)|_avu7&@ahz1iwiU~xjm}lu1;1)F)I+O zptxtBKqbK&Ta5j29BQ2k&e>Yn#F=TDTsw@h>5=Ffb zFQo0}Vgl_eH0jF9`##Xt(?=h=HL4`e7%s>q7Q2`%cDLUSvq*B-c0D}V$(~t%j)6bK z(<2@N&s9OrY5^I97`fGS?MV?L;2Xhf-hBQH{`rbHJA)r0Iuo*XS*ULs=-Xi9>8-)z z?bLI(C4!%fZ&YJ_FrTija`92>hiOj4jaI{<;kUd53lH|PW?Yh-kDH(t?9V@!##vAJ zqXWgiAbR>s|KxN#nY&Pxuvi+r?b9!?Bn449%Ex=`MYN4X~&NQ zqqCYvyv^&Y7>dO-2c}mlKlu{-9nJMT zA{h9r{V8stpbuKO#_b-hAwdi=i~emub3F26=e z_tb=DFhvc$ts1Vx8crNbHFbW_4x(1v$`W7$^N2ZPZh^$$5$+D#7 z;@$N1%(6fB!ciKOqA0tC$`_(SEYH^09C=^oV3adgXGzTNCAZ4%A3)D{Mg4NF4|A;m z%gUJByAaB+1UWfJ!ec%cKljSz+rNcb06Sryt903I`r11`qCq2Wr?3j+s$=#DcHeJT zVWs16w`OYxslJmxDmiEZav3I|GIH_lEuT_#_Pt>yCP zHUXLA>MWXI6Bqe3H)S;)=bc22QzwY#E|_sq{xl21lFqy0kQ|D(s#=-#?$w4RUOMq<7H#lcLOU z0~sdR9F13N@Au2)Zk1M9jQ35ps(%^RENIof5Sf@wPfk&|?4~hJzn`x2kiKL79(Hk~ z@aBu980G$Z4(HO)YCzHb`ppXrfo_GhW{0CXi%b?n@=JRf*~tDDmtT?KX(Gd*8&3 zpw`KRS|yrZuhokU=flPAR!vb1wqc?`99r|GwGha(+Ecs5dLu2rd&{OiLYrSP$vV3s zU1cS+7U4vrn&ID#*tnUp(&-(yrw@37we&%eQf)j^%QvI=56hJYPR?YoZm2tbf zbQ(%!A-Ulir{Upg#hC)ak`FyR`kL;7_3))?AV+uV^{gq=#5FOThKs8dMv7*Pb=({p z(5Lz5@9f1F44b0j(7e`Z-CgJ=gLWkxS}wu@!AK1AqcuhFTN9decT8T)Jd0v%49zdD z{b~-anet~V;n?{8Bb-9Qkc)2s19Tg%l-&C}oWm~y@0|P>Ifuc=!?sVcgE-Bf0a<x(LA+9uQNnd%2}9K+3~;2Nt5{12Lqx)Bv?PZS>htkR$nGqaO%sMZ}^EKFC6YGtI?qm{8*tCO$mgcMdx;$GmiUgN!hCnlJK-_#w#IV^& zShypYeoe);lz-wS3l;UoT1+5}hivFJ`__I8rwC|Aw)4*YAxwaLxIvyN9$hkbI=A73 z)3MGrT|THDM&~v{#~PGA{GIt5)(rpr43*48o=J}<)mvI!p#kj;{AmuhRu5m(Qn3S%~xL zByO26TfwkJ*vtvYDkMPWEhW^BHBh2PrBSJ@(h*0N@Pw%tjZ?ptIQ+VU8$R1ksn#7GB9zgnirCu&wdqlX&T(0DBz%uHxai9!%hDN;>nQ{v_3;8|Z zVK^LV?MZT5uLFy9W33+74ooRuS9#&ogSW!@ym(ipDn9`hd02~(`>UCC$(_N!>u^Dw zQ27l$9k`_FfJqHz#JjypX7eY>J{wKO!=h*se)x_X(`27CzA1i|G$sanKozoT=O3%p znhUjco7sFg&-$5a*XU9SwTz%#Wb%`o{rdJ9(LQ)NxF!3Kl~0M@hJjQa4dRlTe**8N-RkhNPNPa$;aF{we{8j zAZmyeCZ@Ra%LPVSAKKizL(b3N8DVx%%BNE3FgmbmEG0F}WMwRjvkEckN<4_BQ$4P+ z$oFo-r&WHI`c)%CWaj=3y5MR@dP_a|%*A$KWJ5&;$iSN{8F~5eV*A3B{ezf|z3^gD zqNjDIVW{&{w}=vE2WA|r{JaPYw3P_mGHM}l)M1xCL0&e(U+QGB2D5{h5z>OnjJ9}9 zMrz%1C=vEJD@@2ob=;J`a8qLP&z|1_Okgsnhk9}@ti#cGK9o>?2}!lH(`u;+UMVqo?$#;C(mT45hZk6){Z+l z<;L&WM<%VTZ(x;jIdNdK&qde=V5b-WyBtc{fmc5-XKW~)S)Qwl8+E}OFz>G@f`f|E zwauG6ZU(cVHkP7wV9a0I%=$yiSr+!hdwci)hWOyuOTJhkde)@QFkWoK_5{2hP|c3= z&x3rYi)UDC<7E`6XlnTC^u}(&HKAFu-(;cOsorfSFBUu87L%=wax_<5-Fl(Qm~@KI z8jZ)SK=2&M5i)|2*W3&P{ymiF5o0NgkR!wB+v{ZH2Q0BU0w85wi0)t;+c|!}9sb~h z<}QqBh3#opK=x+IJ_Q9JNUS0|#dYX>rEF5^;$FZ!hfKysl!GOM`7=f{y|$#od0yF| zL-)MAjCCJmzshjBG*Or}sib~dwjRP~@G)0BZz;&>Lq2CVgx*`U7t_nfDt zi8p`1!@iO^Wd#I!JT71TVL@%8ZwiP7;o69CJ1EEq~? zT8yIfP0~ro33lhvb&|Q&9KQ(z-HH;*GTY!X{)-F0R8gOXU_aNJNAA5OWsXxVV5gXo zhPoCL^e$VLOiWK4_Mu$9n&ot@R6s0Saoh_76qq!Qaih%n#gUqq#XJl9&%rOR{=Qs9 zRQR_RiHtshGX&8SI4zz)c>c`f%6Ga?&G=r))vJkWcQ=T`(dE_6FzHNQEihA&K|aeq zSM^NIBu~ll0-|nU3pgU(mguY!p(vPTK&6*a%a>F=sj#3-M_W*p!fC1XYA5`3|D!Na z;c3hXP#^y9T1VSfN>OY8p1B zj;l?zOP6((<9A261?${RWQ}^7-R&&kdAZ?)t3N%t*b&#fG1Kx%BU2B85YDQl?&2{K z8|p0vc~18C-6<%$?q3tf_wNV#%8>z^&p@o&7=ob{H~>5zPDRnF&_C_}Y$7raxq7P= z-N!$V)yrH((opAO3&i`+l_-6j0D$ZS*ipWc^86{6d}fp50vI{3uAs#_5@Y4hd4QTv z9@G!hgPes}Pk2AVezBoY=~7s5b&RV_t&>&|Z|zIEQAUpyGVWDr=6wFAe>bY>-#XR9q&AzT0QjHrFV zfT2=XxmD07&Z|(H7W89>CRo-)rZ|{X?GQDn7<$}t8M;R!!7@Vaf$tEL^aZg5_ zGOpeunMaTN$RBwP)Ia6hS>{Fbe5AVH9l~_w6Jh{>%BqCI_|b@t#dp34a19wfBA8ei zIek;4eRX)v;%VK$r_qVLpvH@augZRk{u-9G+Um@O3F@Nk(tqEy`DY8Rg&uPS#O3{V z46|s^dS;XA`JSj3FFo$y+&EiG@tWU>|Fls>dTYY-#362SOcvs&*tmr5bhSl) zJofNYtXVb-((%u+m*KQIUge7oWL9<9Sjt0wcR^jWHmNdVHKs4{p;*%MWtn03&rKZ> z<;xm%*L?y*fe6l|N$<8<{-vA4`Qm^mUoDz^8E8~tI-^i!F=MhcrLf^>qIiYt$VA;DjG_H?BdwXPn)2bb^8qh|6!mbY) zFR&q~$?xb!I2-;5Aj~MCne*36W{nkIoIv~!VRHP*%%xo+N`l3_fuCRU!B3NAJFUJ4Grbgn_ADPUe>EIfhxQiC|@mdRiE#=jp z516WF_9(x^^+>OUloNc|S1uiTy*j026|q)CZAGJ)bzkeSF@)F2CvYMKuCjLAkA*p| z&edvaH58!LJ)#ShQ7+bE3bR-B<2S!17tU(*(f@X_{FmFy|M2cFEfZNl zGG{H`%P+kEazAX5(#Vhqd1-ro{INu2$Gp2$A5PrvzDFiK0_j2$6wO{BCe=|s!}=v# zXpVO~SWH*b{S!-gsD&PO5K6BB2}DL&>Pnm~+6p?aG5y3nV^{J5cUSIaLb}L)7zm-a z=|W_P!sSWi^F7d?a4J{C8 I9h%$jFU#Tc4}JOh?YYln767=xz|3%|1c;x5+QF#$ z**O#+^~LVD^dqrPR7B{irw5QggZbEYguPc%NGgXW>-}R zSY026TihLSbahm!;m~g)d)d*M>9Dtyp|!+YC9iLbOzJ?S?kgW+a}a;f!!Xqf2ZrG! z6`Q70C08$38a8=$mk;{tJf z5HZqzRhN=Kv3ghkk!{>STvEBd#-*e2*IUl6)PzqyiX8nTWAh$jxQ@?5 zp1juQzmEpw8qqnc$-MQCZp7QSA;0C7bJ+n!zuO#Su6rwFq={?)3y$Mok9{cn?>a_0 ztn&Ky5wlz;I79Z)wgvzC>OT+Vf1(WeQ663g5ES$8}L5Cj2{Xn=@3G z>Gv#vf3>qe-R!SV$`1Mc6d|YUXuqGL-1SqO8y8ObM^6y}N%Q)qR6h&)^GbEE3AtFR z$nk%4Pi`RglU!TJvh&C?#kD0Q%KW-1F1)>XhyR80@?SqgsQ&M#h#QG^{fYSlaDLI* z)R#l^H~!I$@Q(bQZbn|1+u2|L#?U9%9*!f~qv{`;o%Qtf$+nqJzT>!V=KaE`rwt=8 zrmZ!FAzVtMs-wZ=paU`5ba70X4WsqHq&7<{ zQaAt2VfmL!`F}2%4-BsOL)qWki|xU6ggE04Q56nKeo~@`cKMJ-l^>mmgA@oi&{U(@ zWGq);jIus99D&d&ft9v$5(O}S}8cF>Q2iG3?r+qfYv8lD6X4Ka@w7zKDlg7v7o3L%)Tn! zE7xzQdyy3!USTp=yYcuXvFclX{gSqtBudOUW-G)n(qDbiCQH0#|5d5>KUa`wbbUG# zm$H4P&ID&uye`9(H{3c#EV#@=;1Z(bt+7{3`l3W-{$O!kjAgxlTW}I|V;8K%Xzymz zA}XVQabFez^iUje6N3-sg%}3(^Nz?A%@dmJls8Ee{@tVf-z_3d_RFs>aJl1$0}Jd( z$_1KWU+GSz`FO1sIuS1^TXMwgXBCk0r?Ya+(KGHx5$DH)53s5ysk5b%!e8Cmlc*_+5gX>R zjFOCdwPm!jMLS>4*jNfP9hg<)a9xk3yIf&A0km70(~M_L?K!sXg@cMj+(72!#YLrS z(s}JZ#)-v>Er;XzdyY-iZeGhUa01q=Y=jTjr>I`&q!>{V<#@(Cq?cFqWJL$%I1Sk6 z8OjtB6>e5c%?M_HP^}EMA_=hEIPENM1b^sbKz^(S!54Hy>;L#?6TO$dfW( zxi|_AE&=^w1OUIowmi>;fX0T6!{(>e3Mg40GAfh5PT_Le2m_RL)B!$gXOnIxXuA%iQjhgFPP#@EX&&zeITBe7|(%DjyVZ@BFU;dE4DzwyLL4Lq64kN;Wv#P5C`ZtfGkm=N>_ zA{wKNna}-{nAP0+{wyDq8xIw1orYm==!u@63gN2{-P+J#V@fSJR&q0+N{vB7U2(-~ zz4rj^v&(HXkIIcn5db62Cv600OT;K6AFe!Lnmz33s@dJVO$4hVLq3XR;6aA#eWo0e z!hUOhf3yJ2?{XKqv-|4K?Sf~mHb>u<3B%>?0$h_yt6zfG=Lqqy6X>+>h4S2w*K zOnJiAFZMT^xf;fh*lwfYFC}3=E9$+%FRp+5Ooj?AiraO09;?q&uIY(UCFfN1uOPcaGG8$(mDOSb$J zAus{5vWQG_^U*n1YGX_YpKS{CY3Z2_+w5G}A2DxbF5=H@_^+kpe+(6XkN6iTjUMs0 z02ZcISf@IqI5bG((JECbXw>&51lg;u`47zbDOyhbWruTnC`lG+8bs<9RSP&r@ZZ;Y0+eYGoTP{XBwIRt6fmNz1+Eem%>*1gqL< zWsgBzAYv)mOER^TPX9x$n`B~@BUSi>tkBWrn>h#t_0kF&zCCwc7rNr66l*&TXr5Wx z#;kqtliFg7qV)04;AWI2mJfm9PYkZwud?NA?G?d*F0;a$(dcSbeL%4R{NDGj^gy7R zxbNIhIoRbPDb6?b3F(uuQawO&43>(R<~Z3e26jMSrx+NOYClBKpt)ZU?=0XdRJwJ* zF=h0%a(b>BqK<8%+L#5C&d2k#qzNEojk?JandQT)a%->ky?rtCFz@Z`#FCCDKJDu~ zZ|%xql+>P+&r2ocZKr$0Qk}OjGJ$7pKN!mdARZ; zS7JBs+L~ZOaQ)=Pn)Jbe0BxP?6iXtP$vW}imc3=8eTLrXC4#Pig_Brrp#EGIP=cCr zxSY#^hChifwPBRZvXehfE+0Hm9vSrpZoRfQVh=ABh5`u5E%EY^Df0taBb`;x@yyJw zty8)25}Uvmu=xD?7n0A4^A8_O3aNUa4ZPGUi|>fzzkL$&%gpw$ z0yqDD|LR{XQSe$&CZbOtEgbme{D?0S-i!dvCn7ySS^L zn~LKdG{$yhmG;-)Azk)iD)lxrFN8#Sjk8piX|`5LO?f19yNG8s9{SO#K33?LIpa2T z*6Ejxc;S3AjI($(2_l+)T50}Pve{cf+f$17be}f625sVCrC+-vcGZ>B__NJqhRS4~ zt&$~FOr5oGsp`mY!rl-x1)3{06kPdLKJwV}x%*h!0k#I-sJD%0*b=e_Z@aPT)iKV; zUA>343198-3E`dUV;HeZ1-T2FU2q# z@E(w!*7=33W{Mh{wR4Z0xTfu>0AG4Pohre!AaJ9Kxlav*p>>YJ7eKi}UN~`N@8bm6 zp{O@PsIV%d@?N}sv;HD~=nUvXqVK_D#3ZO`a^y)yELL0%Vr@)TSx7L-F** zBnu6+;=_&cm&}+e_pBN&yz4+;30LkgkB>l!G*mX^6z}=LjBKIbW0rMiE#KY4BQ2Pj ztjlqZ*rr|X-n*M&(*(ZEIu|Dh*isYbttPPw+2`rW&qKacOv_INJgTSRlcaHap z8=^w^wDjLKe;3TpLdJk2tEWKAGOo>-6c))puh7d{9)-km&gId8+61lqQO7o;O+2cl zp>0`zA`FTD3F0F%dXlxR^;rMPXXLkQET&t^j!9>$f?_GWS>Xk26*;MTXhgR$K)7US z4Og1cr#BdXM`et0@wUt7r% zWqO5rlZ*D#AMGN;PL8|Sdv)yIHbyR>;k3P!$jHmnJ?IZ%yC-+TGS)xLpz40pv{vkR zr^>Sty}0oMURpH_cOW5dJ+dRAHGbz164f(e(Ks3tq^ld?+)1$txdKa!P*$g6t9!Qq^T^Sn^;c@mRUc_ z5D!>9(VYivf4kpaNSUJ+5^@6RJERgG@O(wlb~v#aMDA^pP%s8)nej&y)w}B7P=!evLrv;eOWY9A_n@;%tqnr zynzbcjgqxiCvU$eN!9~E0wCz4{KM}{6_yk%w%5KM1Ogwo_*vB*)r947tM_yu^7I@j z7woZ`Uvp0HXm?!%EY#^0@(qzOtQw)Rh7G*EJ)6@tQHs@z9kZ0IL3ydKe(M9v=EOX- z?a4qcb}{sPXuI1f(BRv0yQ5rnUO?)I-6DkuUy_B8YY;8w3QzD^{tU%|86P%i)Z!l| z&O;vtGotW@3V&2dnG^4V*8VbwHFSjyyBOnPMYR1QHE5Hiicb|@wFB~2O++7m1{;4q zEZ_Np#WsZlx$xbpqNe>J)~KHC{>k5dkxehJ%T>T1 z%<*_wxVdr<&(agFr_UUa9X3sJwBcbmUA*n0yRHb6^qIyxMrU)**K|F5RCEF63YaSm z6L2|p>g11hfG*Bi<;L})qTESm0pGVuSomPhswbl3YWc@s`B6F6$4%nTh+KzH!f)OV zIU^)93YL_AX5~0@6oLNd41wI2Z_V0 zr;*@MB%c6`RRgwU|xTUsH$j6%!l*Ef{Bt@(LGbbp$E&di~xORfB13G zFYO5w@)|-zQ=)yMfWSQ3;v=S)oPp~^wM?+T!Go-lWg)p*x!+~k>ilLo1SK89X!D8h zvdu#t)PqxocGK>?XcDzAx<51^YpSHyDb~+D!av;yvQl>-M(NmBnW^Z0N9&DTe0B+j zw8mujR+WR9$zVYt2^jJ@t!Sx5j)%zS!MPat)d!M3nCcnw6FlBk&sPVnjC;RkH|g{c zpL&03L`;AXJyRmN3dReei(?FZ~K`68aUX+D}qf=BYn?(i8bB{;Ta; z*KYOk8Z!vgafB|en@w>s`U!{a7+;PNXhypjX;R3R{^*%L8%8FwFx%vl6+X|)VY?p- zwcO-(0X_2PmTpcjBZG{eGHHx-g^#=^2a}5aAMEl^KZSrK@Be#>Q)_v0SxA}0k$0Kt zK`j!|e8I{bfRj<@fn(ZL{Uq#oLASU!r=mj`F>7(Fc=r9w@1UUlk~o$G$7#hS8j}h13V-qhTMx4*Mb#;x z9XKCUCy@X}FMNQJVRzD2!K3XQorhXwg3phR@?LwpGudIO8Yxmd zb}ZT$OGhwuQ#Loi$UAQ(xnAKEl_GUAEjM(>5c&qP;VsrEjcAIra>xcGL$dxQ51eVA1IEET;m`PkOnQqVD4~=xYZNFR)6k4&^!fPHPbMm9eGYC=xU8DgjIC{W_sOqWgs)^ z-7VDdfUvt0p)z>cViCf&`kkb4QtaVy4b%VrM2Q!E=cfyNbJSONKrbLM5RbgUsQ5#E zs4?P9U=Os!Q?J9>9&tWSUio$)3sQ zEoO|ulgeQ5au?275yV0}j(fm8&gwAMM&Upe)c& zAqMoi<#Rh1VNWiCdK-Si<>Kkmg{=#zXItpdaco)@3COg-x@{qOE;dCH39ok>MI(KL zr;jjKzNm>^!;I_RCtJ0Zz)b5O@4_kU450nw@>$VBsb~op{?y2=9qJ=*Ayr$XA+^bJviz55nd5H z!IN;tdL|8C)#F?(k^nG1tcJR923SPeTO<+QyFH0!EPI>To&uR>!3Dx+w% z7&kOp70b{n%aAo$nDcztFmsFPPw~=y8l*oFu@LKr4r-(_Klg5%p9tB=k@5ON#3q`O zENf4Da97aGfM_W$O+16FiR`yKx84NqoZD$+{Vq7B+v#6=8yTW*F2auNpDLU_pq3|h z5eU?PSVlzUE5kO7dXu#Ra2or9Mdm`ltm@E7j&dQr(G|D}{O?d4KlksVLWVW|M3q0k z^I)B8@=%tx&S7hSQ{M{Sk_K9RMH$$No6X@)e}9ohpiY?m}ybg;HxdSpxMiFlNL!r=HPEJmcS;EOz zcaX&Hc;8`o>4W4y`)G1%YAR`N^KxrzwLW>jt4BOss*EEqg^FuqYOiPAawB8fwI=Nc z%xTLdAqI+yijpL^LWM<|z*2;|q0S~ZA=onRkeAj{ZQpcHG`4R{hCi7~C_w+2SJun0 z2TP&t3BgI~0vDXa--ZlBoGl?>*|vmAk-+%CcLXK%%9ZsKiFMAComHmHC$GmoPjeH6 zxe+oAe7g0`^V{glSL6@K4h9UePLIQ3%26{F0QL|j%^(#iUxP!%;&L1}B;4s6PWoho&aB-9dQu7LyqMg&2>RpH-i^TC_swkG~?lgYeQ% zFipqX-G#*Fr{Mjv0Wd;vj8Ckn8IW!IS5JxM_20jhjCg?f{ssyE9nAmyWef?y&1M-A z<1vP$7*8&KpZ{HgUNOn`&YV$02(Khb38wW}UIh&oQM2F=+;CduK2zOaZ{ z9=lZe(F|P+X?sD3R~#O%uZRw}n1h+K-?tYc+( z4bnGiQt@gYpQC~?l1^K2<-ye5u&Qc?5lqti&r;Mbt+%&rf(af-h@h?AUZx^`uz5?& z3WJb$QHcjy<*&{{vr|WZNIml0Nf7%LIS*;6#X;Hl`s2YIu4yl4qBk9h)I18bPqLr- z1@x3J(fiil4&Ht%kE%_s0zw+ZV)Cb*=uN z;_tk(H=%u%A$dbOg#qo@Rq7dMqXRyqse>iq*s<2$JQwpGnQiZxPsrD<8j0ih4=WEL za-pIE4?NE2aqkg6*LG=il_tD7UT*M1kJEt&DTUALhfCd&_(R&Ry`KxHWSU3IT#2+z zKbP894a$RhH1>xHsU!~J_Lf>3GPfnwR&Y@q$!o(sdd@4+W z$Z&LrA^VBXV{pQdMoYA%vglM|!{Xj%(vPY@ick8&mTDSgP*>oA@hbcF`bsOj-{K%4c z*m6XP-Y5dQ-R1+Uv$+uVMA=xNq=XLpgnCR#hk=(QIYfCRI z>U1O49h7DbRiPxJxEk5Y*wSx-XFB6!ciUuo@Sn~^sLvq^Wo$Yq9U3wdEZ!eLftmJH+<1^_} z|D2I?f^$Eapy`oZwjuTxw-P28>Q8U#y0zJ*OxY=^j)&|x-7HV90z8Bcp4U#$3w{V% z<)XqXyxLomVaIg8v-!+qe02RLrCb^ke3@I0Y{NbMj>!9jJf4WOD#%Pet0+VH8u;;S zW(5Jfn4hFs#H(D_F4vx_jYbD9c9?p-7iEs`(W&dW_wnppQH~Y*a%y$*OX)(*pyvO$ z%-49{5mdb;PkBavJTJ$&`fzsJ?L!!1z(WQk^mUTQmyflvstLhnjoSvD(eE5BG+yN? z9vUgc@tQgNqmdu3QPzex4 zm7j1p27G@BY}AL99zS6nr^J=4V5VY9A8O3c)aSfJ5~Lcbq=-uZF^An0HD`|Lh_rpH z>*I>=aKea5x|8wMPOE@I@F!;quZQ2IB(5B0Z;5n5=rXJ05dYKA-eWJdVaWpPsK>uWFKtR=C<}VGyiReZ|oDUO21Qwyq!80Mp1U*pQV{Y zg?9MZYRqXzLE@CN)NK5q_``%N{Gm%TJmwQmkZxn( zk$Wy!4Cg5kn3nU|t&HtNlsIk(E5&@YWWeO}Kf33i9gzMuSNDVl-4zeC3Dw}%{9V2lQ%QAtj*6CIsL zWN)(&V+dP>3pV?Sn|&xprmi8v>=KcV{>FpyZ!$&3)8@V{c+riWXTe_WKGL6DA1#Df zs!-GJoSW&jyCagQn3oheI3K@)MJA9GR&kle0WvbMUbiHQR@hV@5U_OyX?99RVo@!< zw%6H2zAav4jfi5@LP=1})Lo0Um2O?(SKsxn+pVL<4WH+tNO)i!3}*XY!prB`oYeXp z6~#W{Q(3%2)_`w1TMIRjPUy*bUabg@dccI5B6;oo-TU$v;WHVRLKRU)Jx(h1_3@Gu zi6NG+HqZ>rR8-=nJ|dlHb=B4s&?ZouVUigKxt7fRj?-}6J@$BJIC=_>I6paZqfsuv z0HVnFNVp8&poM=5)*k>~>LR(T*H596>GO;^Cc{R{?^LN^Y{I`aSaaog#XO(itn$sZ zA1ze*J>6gRe5qV9yo1!XS9&!~Fq_!>s&$>?#9D-P!85xYe}@Zajd!z{DI8Tdyx83F z)@Z8Ayvq{hgTMYyDESwn{J&rB&d3ay(0<>1jd__!Dr6IeQ4~iD3lc$7Tw1Li|vI*23TGhSYvf!Mjr4s{_2p$<(unR7wk({ zg&Y9rs9PUtV5+|1Iyt`xt>&*IxL@rO-}cAhE>wUTU{4m|pI;szd@%&C(8Q6gnh^g6 zY!Cfc#YaY1^G8^3L?}MJQaiTq5)oIj!Mhlb6QD;qUcsF%;A9lTnD+^HVIa0!Yek-E z->ZG$>r`*`Y-uCFe5>E(F*;!!l}A(RY?ey2RQFz8LZp5hyTQqgnL)cnUI`?QG7mSV zQY51P3qXM&i$N0dJe}MC51x-Dt$@5|UR7^J|L2Y8w31o7iXPEPXdf{NDNt{Y<}`1g zz@C%7FTc4e41z3FH^my{c|e~z%G849$KSF}v2Wc9Jd}~8dhTUGOSlh2;3v}ufQQ-4 z#!@cpKki+uiA}(N<{U=!IhH^_gU{~rR+B383>u(T$aZ>ZORioU>TU7+SpDgw#SSuA zA>J-$$Itl$O#fwe+dx7Pbe82A6dCL4o%5(+HFuxqaX2J$zaQIj(gs)2BTE=j{rf4| zm)`e7`R?_{I#+Vt9>Y#=4};#;S5Cc#OP6ZQ9^qP?*L}6W8ML~(r#KY^8?IE7Cr%9e z&V|kPaH95yfLYPlcO!XzN0iRd-6b2QBc)4cxb%sE_gCK6Awi{8c3q$vJKq{sPPfyH z8jpMzF%DCV(bBpvDbw6n^FQ89k z2!hmw0mEO8Gof*+lNxoYfdWz-*QYiAsV)A3Rl=_{p#q-nzWJUixQ{8Ad=Z3o^Aw4V zu1risanEl>=yP^3iQ!u^h zWVqO#M)_5SBpS-3Gy4~yhsr~Q`kGL=cE#BZ>p(GQac^KayrRm zk)1M^*I{1Zr3fGJ4fdBUp_eC8=YwTr`ON7qs(cAFe|h2+k>7BPi=wSwWt3HVf|ZYC zvU9^DP`vJ3wrldhRF8@S#fA@*YMF%rM|ZR}p5wfQ+LtE7KlkGVKJb*W&M(J$KJwN0 za=}z-O(5bgW_>C3X=(L1bO|O84K%!uhi$bjqAT_s59<3^61tRt8n%~*e}Z^qK9Pbz zz&NrT)OEpWy9zt1UZsvYCAi%{j2O_)zV{Efn{_W-MP?M-JlstU z<}sa&c59u1fCM3u!RoW{?N0t+F6%)Td{-TiIkW{Xcxdx_5xKZ+MdYPRUhChQ;bf}Upg|hS z&Cc1Zf~s_hml>WOV6iufEk2J_v(=`=(k#YBV>MiN^&}Z(tr7SW!lOkEYAzb~F6l_N z%PyQ{Txy026UQ>@6@lZzZFe6>lW1S-@-}Wu;C_w^+LbZcNt3Jjw8bfiK4Ls*hAAUk z2oAmyUC+vlOtWPPohnERH_WH*S@lA{N5|yp2`);P3zyS&+q+5u`-Qk+g2h7ch2JP3 zh$+DQLWpyx5=jy}tAJpXhKB#1J;21=S*_IUzyVnMZ?ifd{X+Lp3K27(r|#E3O52fk z@q#YrM)8?FHZ>M&ZR?PBfkWHfZH%w#l2>E6YDK`o?|gV18lw+|^4*a3&&6ysN|*P! z|H5)PM}YUc(!SgK{P!R_1fQ#_P(^9^qI+!i!09KjRQE&XkOg8Kfy1a}3jNd5ee%B1 zC5@yaG9yU2QMy=;aFkRkRfi@6HO?>{3&fg%9~L4h19J{~rY$OqDm6ibm%>k*%_wpGVVKG9qtK)b}$U*6V;y>su5lqOxP9gcP#+uKL)d!zz z3^uS5pyALD(FI!FIG3s z#~Z}Tw3x`i6IfZMrbm~;vq9Fi_n;0SS)7>fQi!v8-!z| z0&{&9>kX6MrDh_;HMT=FX44y(k~PbzmUFnB&Y~?hT6X6p_yp?k)LrGgk$S&U>%;|Y zm_Q*S3V$C6=b~Yf9mKhUfe9AP>C1rzfL#zRwr&d2_vF|RUnemLOtZt$yGU0S3@njy zhIg-4J8sFwbelzR?)UH|dOWWNFw|sZAga7tLk1?L@~auI=G5aVS}dy6OY#hW4-EBf zRu(}F8m4N!xj*k$he;f}is%}Dh&hW=gKcdx4y`gXYxebFi&2-91rfKsREks_DSbhmH1)oR-NkPx@HQD+5|8Avi2AEvK2cXjNObX8fz zJ{0hkV|04$;muZR3KobYut`GNy$|@0ml|~0zy)_eL#u&LfT7&&SUkBNAQr|5pHM>` zJOu18_rG$7rp?hkqWWG@D@gm^B`+RcCbk zp?IErv&5av%cLX2tuLAF#vRLZIo5mgU*M$$AQ-g%!kQvvX<+-5()!#o8$eO~!yqep z;*kn{4ycpWJiT2v7M{px>8($$i3QtAhxEw}Mq)xM7u7uJnw}tXT1~(Cw8riY5B%A% ztY)&+e7~@fnLie43E<@b&i^jY`$R0&F+3QSRq@j4Q;ZsTk?l=N*-D=>;Yy#;B92&k z^=PU7;eQnk^6U61qkq_z|H4x*3j9q`JR(cH{c{KZU1$7hB+32_crUf#fBtBRh^*f& zS(bjfyTB=?nKGE5r353y&2*UeC=@N$0WK3KdnCpp8pwSlz91tZ@_#c@pYMcHBvCrZgLx)2fzn5hX#g5 ze|!ENdiNxqnx~%|0GlJ9`6f1`lmw%3}qAC*R~qIBU^9>DpH1V|8U3*q}v7mVit7pzZ7@;ZQ6~f-;)i?na=O zVx5&`f@oeEMwp4AGm((XEAfoE`;qx^lA&Qj9XLfPWez*l>6Da@}KbPen=>ewY#K1J}912h;DPtZ;z|HWd=10zNlT z^PdnluS26Vwg=aJUx)!JNb%Cg%a!#_=)(EW4Q%`SL)05V&u-jqU=SM8{pEI0noXt2 za3ryUgX~qKz`YKdIFjGhkiW#0GVH%d1Po?LNMD_9r?X%pjgqX(<`;yx`9-SzF(LC) zk-7Hkqqz_$*vpGndi5&d@0`%D5$Um5cX~Q~TA_JsNrfDc(1>~A&epm@fl$i(;7e07 zl_HGznVI5Acf~Mr$(XA%Ea!I;zyOn6sIu!C#TF}F_imhQF|3>6h9j;Gz zpeWoekYplx#ruZTh!d}@C&yDZPwYVqMHNqI(59o#oax&Ry}Fup4zJ1aVy%atf37H; z{ou>DhPO*kw@IIY=tSV@Dlfe$Phhj%O6S`u{jS#v1f40uN^5qO)6hqN*wAsDn1 zq?25Ln!M-}OG>9k2M@b6_4sE>fO+{+1d?j6Mz^d_by~`s>v)38u zarKI%O0TUy9l)5cTV5L8CNOU*?V&L?^g549LD~n`+(hAS3_D4*6_CIyl8E`H}QhNKvjX>_vZj2Ft?J(@3M1=?rE@lCl#5#zk0n>6fp6D0G`QkS;ays zu8~SK9F2J`IAb_ZmOJn#vb*}qkLD{29~sUz`$uJAe;Cl`qDD?4il*yz zdc&r3!q=YFw4Dd|Nd9zc$&fW|m$;^j<*9qFWA@%{j#$c1$$+~tyxr&Gc6h=eGWNZz zs8%iAR4kIE9ZKd38j7HpXEUGdJ(w}yc-vO&v^RlxeKtaPnBd|IO2jliMp8%;^xt5#_X8D0k) zw&*QC662~|PtTPvfGpZJn#KoXNK==+IucOns3*Snx$4<#dZiSFI`_eFbxd z`b5;f4uAJZW1Gev8`zPY#$nr+r9e5S{pIlQXT<;3PygRmF%R_DV+9hD9NQ@S4_O`; z`ERU2ILsBk=9oa`)pLnkt|q59L)9Cbo3G~b`{Bm#vkxi-NDZ1^3_jC(*KAYeD*_kOz5w2^d) zBxHk=B@t2+6$4DU2fY-BQ;t&l_4%jA%uI(H;3KQXGciQtiC zyrd>)XgZi(P-UyWP2tuG#{8J4;{EL~ifS;4P6;Oj{j}22QOM^8EPIh*>4>5i)9@Nj zQef(U!6`a}$1QBw8uI($_7qBuE(urkE)F4%j=KaPidhjfz+y&xnCv$*COseCPtu{xk(m+ENoz&?U}c%@7>C6&%D^ zwkJG$*0K~yuL_-76qNm~l1ezBkrx)heQ|*KwAwi+wWa_vhLb=THS~$ih6KS%TS+y` zC(+@OYnEqk1exhtOT}S|hxGYSK}eHdg3Tt29!4go<+J%q9x~WDB($q3A-XND#8A(a z-z^`FY7qBWdZVPG^47&A0-TSRR|;$cZieFforKZoKr4Y3b?i0<6<>bTd+^EA^|~-C zE^9Qx+s50vP=toe-)J^?64y-@Srn^{Sg06dpjHa-+jR;7`au7qEwUCoG2e|MtS6AK zP$2xHk%WprkG_H~-KPZJF~^6mftW!*Ta&Hh=iS8&RW|5jsWN6eKXoZWFSUGD$b_!v z0psA&`Tfq)OsL2AmhdDidM_?Fp-PJ|O=})QM0@2V=NJX{l|BxvR-|4pej-XcwpctN_X0OtK^dTpM&uV^M z@BGzPVn+T)sEYx06XVyx{cB}Z@c1Qs3hiIg`@j7kWq&ou`F9h-9KG>{^yNee%t-e| zsO32y8a(L=bN+BGPwL3bu!`?$C)GOz-4a)M7D| zwX;ZzRJ8qzL-F>b5lMH=%=wrZ5=lWQf)qw4La|0KDj}~()D&lv946lTBJfeR`Q;o@ zeW)kOc-A}Ha;wFP;>%R-vfDg(tY`HR9T)yoCw|j#VZt^NA;8;jVwA6Ff41_Lc`e`r z#8!(Fjsi~5`&Uq@A}cGRN;!jeE4Rr+qMmtu?g*Y!N*WO^+mr`s!rJ}wz-(~{>LKiK z%7-$klKK5BCJBw?L?3`#OF&v3QIlm9A?u)*ibI3Kxm^Qn7ij%@BilF*%ax z#hiA z1)x|2i7T@x!#r&S9$nY3cm}J@t{+Xh-#k*+2T9c{ePvDJQH`CFv9NAdAVL2P|E5#u z*Mq_8bpKT|ZxuwyowZRE$0V znrnf4YQP>_?YfbV^DH18;4*Ch6;?zwIV-S5H`ulIMWE_N z$0yGslxRAq6fI7>5@m>(pOJ6)Wvh6UbUU>rgZb=A`pMj#w9t}f?V||nOf{VfJwSo2c;~C+8 z>DJLo?p0|C?@MyEUftxx+haCbkjYp{^}PAX+E^TzJRYzKh>GY=_km#StZyq8&`)sd zwV6S=Hg}5D2?)yvIM-)+)mf9=f1b7@DcDB z)hG`{%0k2nCA{S!Tfn9{1DK~rq^!jz(Z~4@vAliw*mMpfmR{dIhX%4tAr$(g-XRf( z@hKSas&4^L6^}jAM4R^kR8?g3@0zaab)B)E&fncn5Q1DVc~RonjXg0}_+H#%*j^xF z;8%_k{m{Jzrpje!IMwaGdb`PwRRyId`Hbkqf^eO_kKHVolgbxv!aXpE9t*85R?JCb z%lu5)b!)%zvW`qYeM0#)UAORlM}TtTbrR_8M@w-#dY{XHEAVg^j2RFJ59+c*!WkOe zZ7$cbYyZ6bia$??_@A=)|H8VzkY67D-{?+HJ;qh$A9SbW{};N$b&IIqt=*#5EV#kI z!sJACJ%ktVbbkF8^;pXFt@Yc^4?|J4VI)jph?sdA_1M7&*C)KAynM8xKSJ!22b{UN zQvo!^XQKjO7A`u3_6~Dzc$i2JAWE(4(dd}NTWaelMNBL*UUuY$g8tArA}YHKMRNNV z3EWEHU4AExo!Ow@vf`r)6NaTWm26&Tr^E&?ofvbJ6yl$MKlEEXl+9WBpB;;j<&LM| z-0zNCmuMCyvcB`U#L3X`xIWyWp%%-V$ruf?v_A>y&Sd~Rd6BaV>7}>?8Q3pI(Tg(B z^F242kM}(J`K@R5h!XM}0PfrVz~(s;EMbsZ((G`B7D-|*%Rc4G^syczl4v=Zr>Xxt zr$6H^bDC;#Puf+7<277!b8tz-W|j;dQ{I^COSdrrUpF=|t7hVe*UbVE^=M9US-i;d z=#)QVVPL#J<-C`8{vjra%MPU=?nld4(JsBrmaUEy(T}AJDrE%JpTar8Vn`JGQV364 z2>Y1eDf#cqppqM%7Dre#c~uOst&7_CMh$KuF%NYaNWE+3QeBbg99>f4X#{@tEA&ai z51J<7Yz@+?`d^5LYEfC%YJCJKj9k&E1k&TVEcC{JmU7tq_Vl;J0$MQ!C&jMY+45NC z4C9jf*97)xY((PJDF=OS-w03syzpYhu6i*DzvnL)=aWx*4w_lo+ZQ@8AS^ZWkuTL| zCe%jfu|zy|EIT~IX% zMjV2o(}fFoR(b#>u_tUR#DS8d_GTl$xcN;kOdE64>Fsj#!#l2oKL9x)3t>hGHUOL zb#)u#deunxF8d+HvltI-ZwY!o!6Xzv)K133x9il~zqTjg`3BiGin8U6z~s0kW{$;X zwjUtCtDtnNvI!qa^=7Q`3GUi(qt;L9zyK+e2@mSS`UAG%*Kp``nmzudgab_xGtZaT z^clQ9(U{Mh?{9#lE>!wTGYKu$BOjmx_7xt>nl23vM$pQxgtXJ#U`4>{e~25yP?Vhw zzJ{1IbDoII-p7{Al^2uOEzr^3d?{>cXhg?4&b zhoN7GUi4UL%w#rMBrs(hJ6^7h^SKT6uKv;Nf&7NcviEW5LtvRO71FY~({qHGXlZ(XGgx>Y<>@zmG58POB{}UV%HHg zX9TgfFO2^9k=|qzh)J${_xW6K(16*UsV~~reLie*?h&1!>}Mo#L(tGd_4@nZ4-I!j zcY2rCHzwhY!ybhCCNAUim1*=Qs)f*||39rS@!!SK6+f2qKU?4Ezl!5QQ@E#avI92A z9&jX?exGlM4dn624MdN}+L^7irY7Ju@zd$Q@|-x@P=nw^)SrEqD+~xiyQcrbgfl*( z#C-t?f0wz^3)u*CcUU;>VE%3yWU(n}BMD3DY$P07z~hA94Uh$@J}`J1mJ^yJgVsr$ z4k)~DQTG>+HwS)0->^|LQJ7jK$U;z1e!O~Dm7uD-jc{BdvXrAF)1QmNm*%LYEN3L% ztz~`#;NRXk`s9j~xRXjf^7G5A-i%I^GDf5Cip6U+E~B1GFxjcdxvr}r_D_o&K*7x7 zb$b1yczn}Kba2n(^JxY{uFV(ISbHw-F$#J2zJ~!+E8#)c@tt=DQP_=Ee)7WQMI|%h zrF5r?2!Ow?m>WGDPJ0Zr%j#CY>;1?ZrKC!xWC)++T7SSwE*G63l|Y|75hRr2RGtAe z_*wiuBsZr*V?)emh9f~rI+{{h&{w)%s5>Kx!wHnZuyv>(k~I{9q{RHOK<7uG97%}S z*Y%o>2|9Rn=b+U(Yh()JY+@yGNT0y3qZw>PxxM%2p!1tlTj%cYh8+skr#iYU5S}RO zK%F5IUZM)1mJFu-%! zwc$S|C%P2(t(@U4^S(J2cyF3LSFRnA%@tiM1`&I-->d2{^8Ad`7x*V1eDOOazrns0 zpLoZbhOa#0<_lxmx1fuOyrImNsZwnUfy)33^#^oLp zbUUT`LjZ14l+m~z?-o=POS<+A_|3h24b5gS63;^}d&|tdbcJ*SPB=gI$G8VrZ~J2o zim}7k&GvH(RFGq*@2le<#ABhUNS`k*X3Y1e+=B9!PY=gtJCRGIYv&h>+?KrD_5e!p z^vRTf%M3#$hzrB#Zu6ycC_GyRZ%i?uz<>=CY+69`LQiHNTZ)$FXf1w|NksqUf$Ots zrVv&a8cU&Y)oGgcZyt&8j9r>ihre2EE}$w4lK#y>?PPklyJ)R zQ7Sd^DA6f}%K4g8N`c+?U2n0&sm^FLjO9+JKsU51ymfV|*GtvsI~;b9w8~_qAZxtW zs^@qj8D2TmQ?A8Sk2j)bs{Qz3p<=V*>sodMQ``Drv2!d{b}`mesfed!|2=k6J)L?3 zyhM6+Ep|=*kx9_SJ-J}$ELCbyF)BM48*DvaF@RtXntW?d;!UbnuB2akvc31&h*;H~ z;bRX*5Nueqlsk@er=UhCg@Ed(g`!@`XyIFu-yR%Bg~jo-S%qn>65P#}SFYh&kG14p z_h)1tj4%D8hGoUwH<$L=ukJF~*lF8?hR*ev2o)HYu!eKMIT5rO4c&6}K|^xsfd<

    VxEF!0|dYd|DANyqw97BYeDJDVeg|d%ssZ{#O0!;_FppiegMNVGS$B4=PW{yC)iK zFtCHLXBf^AUiH}7`8bE0NYL{aK^6=6y-1Oi-w0b6Hno{=*fz*;MEhuLZM7Da2x+aj z!e4BFYFw+fgTm-`0uK*yEeC^)w?gYJ3|jw(a4>0v6GXM;18PbWjUWDrKgPiZ$JpbO7&qCizhA<#D!%w$Cc4>aBMbpjJbxtkfNZl>Ewxr4#l{(f$9zXFI`>cxO;L!=8Mj}#D7eLPBf~P5TWRR= zy`K8Vl?v5d6qMs58m^T-yg@{D*iQisZ&AcHYxCit=#<07f~5Rmh<$NkZbKbpPNB}!bLnuVU<%*?~WKC=x+b6RK0lC>9(7yL4LjAwP zp&pJVbvAH*d5SEzO~?Dm>RND0L}1@*-AZaVvmC`?#j)K;jYW5RwrY0SqQ>0zx#NKV z3TeoH+@x^SAKFv&OmFp$SBi>3vlXjJvd!%XMKUJyXXBSI>@+Kb_!Go4sPP4E%8q_9 z57*Yc^`(b7rk4b&a6js9{YI#IT~jeiftoF7#IP$zn;nru_@?yC2T5}N~weRd(FqbCYh!j*9>~k72)LX1+$WF#sMMu~L9XYpGPI`LFGP)6gm4}l zO!3dNPI^t$A`}v8gZqczTsEbAi2=+}x3e|$s-q2G8L{l3bACkhy9B7%g$J61FwkNHpm!t`CMr18AmR_D8 zncVMw3by-PrSasIBEA-!Sv9;FI~Y0am1ut7l=a*Fex<2evDlLb5B4Q>`t#3o9;swO zXr>it5SDbblxttT*}aWK{A1?cwcf0cD1ytPdhE&fR4?0a{2d#drJ|c;SP0_NymJwr zPLhDN`@kFET~PG|ukJYy7b?-BiM3OIOamDW4Si@c7i%^VVRMdLGKL^2=QQu=!`oE5*=vAg9NB6ycZ9>IM!j8gvIhc@h1wL;!O60;OP{)75Z-xxwm#99_jH9b^y{ z61?%0uxDkoDo)oCZzhk}~-TcK#U92?$(SB>8L zBjP{ZgVyo6PkUPO!$&U{?-ZhaG&t&k3cP8Qo^sN!~hIZXuXn=uzgDMfFPS3 z!S8!DZ;OD01p1Yq|Fkp{Irc4n?cR#`*h7+D54hERM-hGMJh>f2e2vS3?_J(Ie@>pc z$@w$b9Qx&PP`v!Pp{9J9XhtGl08UY|tRR0*fvD-kT9aLcwL7!(7N*T3X z>qG|4NZ1Kheq=?wB-Xnn{XA7lJ#zTrJ79mt;#JYe6VDqs4pA?Rgo^eK=L>#rrFp47=IuK zmlS%zzZr68*y?ytfCUq!{`5GVXDay|sf?x)^}u_>~nRB3PcQd!g0s?++q2Mwmgx`a{5)QBEd2aiAVusRdQspEQH_wC&sT+ z>l&HA4QL)#muF~V#KgH$0CN9PFVUGKA z*Y$2NeX1!=GXB9nU}XP&t0oK(>(^6^OqX97^DKv+Yy2%qYk*DxP$rFb3vV(8QB)ob zBqlvp_5NjI!^dIJ(Q44QM*f-~!y{7gvbn=NH>1r_`K5yFO+yegkQ?;brnxbSyn*z+ zb~bW+v#2ia`uzr3j)#BZ_>y-rTPS#BC!9|0E7Z30t_hc2bjWtT&o-YJ-ur({Wnl&2K~(VDY4Q`@E>DTV5^mpatQ0}=AnuSYfF0V& z!B|xP8<*z|#q4iKb0%~tB?qM4W&PmTCE%zi5@ocvroh~&J+=YAw+$(AcEq-2ELdhN|MJ?rXo3-PveyjypH zp$gyDphGvhdj~U~XqW3H0cebwds!XwO;`e__dOf#Xz~=Loj5GXpP0jAhg(M6y;03s zLp$dZRGBCeD+QgXQLERjUQj$(DVN1%q=0j&t3~>p?QFkxtHx3VL!A@Hr(yD57PC*x z*WpKl7ZZx}o9+l84md}9G;2L_#8+>JYAjKn4GO>5q{&LiUEToP-eL`OG{YD9k7Sn9 z6lCSfdAe@EnAmSQm?>YFv|mw%^Vx4wFT17ulJaZs?i&q>(l+>&azUjfr(TV!0|&%` zR6m%CYy$#Vif#OqMGjyC%$GzBjwYTJF4*n|*1{qa^AdI{grYk^4Zb7ZHY-Pn<9^?m zj83xn8rWjAc{Ox%WAwtKSmZ1{_cV|5Z^Xgs(p9b7ggDSj0F{rhvO0Tj^P?G8BFbTB z9LR!w1UwL^*wh}EuJ^FRRdZz@H@odGcSgy%l(PQ0*Z+-+A$#+8Ph;UtYkBk^J&p9= zJ&kjqMe_agZ$2Exk9yj+YJ`Zd0M@HKZ}5nxdUWCeyxFYrUI8RsZy9sK=e&ivF5W@J zqBpxSHT%ZV#J#19!^2r(spg%ZTT-TPjmSrNkv%78k>r_Z+qY!a^J9*>kWos*a_i;gcYb<&sw&~NF;;w8wJ8glCxuP3R z(%E`f;B>!8hC5MsQjnT;pu3aXAg4Wzd-lH7HD*|xu`Vj+$vEoQV74~06;0*BZl9q; zLAIh+kzLt?q!Z1fph^@3Ni!xD^0aZ)Fy;eVIxRMre-#JodD~!)Bb4Z<3350;(WwBc zCQABe9NI)uAmUs45N@3)r2o#|Y09ml-T9ukxy9>mw`HRq6oX{i;uS?)%8BzJhRCxqyLpYYRa%VaXD4$B~erqsvY(;vB%>=ovUx;@=D zB9N!^3vBKi_E_ofu1M9q6j|xOU60asGpvu`a}D-vC>LIssPtHyjZn0f6n9f~O-`U( z!Fe<~M>)O)qD+8!K_QEQ_Q~XoUX`gAKxwdVMxOEzi1-}B6Jlk)*!#g;^j6_n%iMK( z|3)g7&jxH1e^_6h9)X50C}!Q(8LZv>W8k^MU0OPSmf=nX8_i!cx3 zC{uqev~GFK}I{9(_243j-Q;CbV8_@uLfp$PJT4tXTT8-b#HR{H8Q~w|GL#jE3qm~Rt)ZRtFFQz zmq6(-D}|&0fA+L#RZmGwh%WonZ34jT8;_bnvAn@mB-ybQTYU~ z_Rm{rkq*~CPf94l!s8vk0$ku6vMLG|tz|s0v(e17=yN(YYk>^3v<6{9@+ALz5hyCK zm?Ob{FveXWW)1M$_7$MPRB|y+0EHFFI;w3%u3w1ENwB-irH`qJ)YuFU^ax_+VrXWS z3NdB~VHc|x0v?ZVPHD@h8u-mbfHnx<;fWsfGf*<|nV`A5Rz|YW=G{z%r6`1$uTgE! z`V&dZI9`y{lCbtzRP^3FH=Vix0kAcCtwQ8aY$El+LWYGyD38r~UC=6?f-?u3mp4D6 zfD#qrsmdzgyiY?U=!i0r*@o~(Fqe~%%pJ3w#Rx~Twvkeq2~NVeKioksQ7nqJTK0jT zd>;~-s_HV22ecNyfcY0dqHj+|{?^`~AvJ0)r|g!Z5kV)1n{Q7H&ITrRlu>Nw&0>FclY#xsi! z&4xMqC!j;40|yndE*zvDDpbnpaE6l8_1kcU6E1ICh}eSwvlXQD92snX(?fZ8w?V#b z?w_w*{J|0*p&bZ&0e#zRL`}uuNW&*I4C*||5ZPF=*LDMq5DM{uFzmPSRGbx*H`s)O z(g^~F_u+Hiw7FFfSQQwSlPp<4v%?dflawt|9qiX3h^5hg4IQV5#vgK`-}O1rh?4HS zih#jr8`7=#2l~6FGvjHo+l^g`hQ|2kB+vWy)j+6 z(e*owN*QR03~)3R&GJc0C&%?tfS4P{Nkfhon&5vOt;}rCZ(lhOb0KLpDf?zem?r|B z3g72@Y(T9Ws79nS%mWt@{Su8;lKa#r8)#z(Z;QBXRk3_pbSi!S)Z^Jvk?PfcWMMJ) zHPu!7gU9gnEBo7&iBX_Q&AS5DJls32UE#m$iO%%m&Q-0y-k*YntgBDYQd=gAMo{0q@z*2Q=zZPkou{9fziHk8H)PlU3D zOdfh;j;5@i=(@i2tO!7UJy#>N^<5nBj)PIa-39jh6*OIg{qxvIIRINU+M6X4=i^UY z1erwQSkr+H(1zVo=Bv}tyMEuKPtU!fwkfO&8w-|EZ%MeZJAXS{t|G_L#ZO`JsCTa4 z7^2Q$t%DCFhx6EhAdM+28==fz#A6EcQu-ut{%Hwj*Xu?4Zgd|FH#XJU?MBT|b6g@q z%90o{!IPO?DA)qt_XMhO&ctjQg%tE|M)8{b!Ir^7CyTqvVZEO%hMws4FbpEFzTOzIiwX?Q;LcAFIEeFZ12~I2%|p4e2LnK+CEA z53NXF5i~?AEAABbqGLM3dBW>oo?fhsW;=k#xgEdbUt_vL(#a0z^eqRiXnMQ!v;A&H zcUBhvXBZ&cBzj;41Z>bF&$kz?Y1XmTLo8+mzjkM+6Zvc`aSaU6btQO~o*cf?v1~y1JM`TbR z*I&EotUI9?F#Lr$$FfPfw)t&vA~X2)?E+3!;cy&7YRfco(Qxc2DP@y@JBOt`o4c%o zpMo*OLWqOWncLb`O8IoadX)Dz`nSzi*SrKmhDdf-R~Ilufx|e$kz5~`fNNHwrCVcf zxrTj`mQ!h6sC0M?45P~RlLS^VX zlG%TyB@-k?6lfLJGcW1oegf>kjeq!y+VQX|zXFU$%bT95t?N7H%_Weqk(8q8p{Xr{ znIf_^n=lO8Nq?l`J1@~#`-@wZ^XC&s{1NQ`d47_Z=--t9l?h~<`X7~m@UKb`Z-=9E zI#aBm_|+MAZe(9kV8XPZO#WTun=PyD@4m-Fg5PLvQW$uuk>TI6n44gOuW>T#l?J1Zv%iC1JHD$dEq*MK$mNd9=M#vBSJxUmPoHJnvvz$H}nhGwzsnb*sw(wPJKLZ z>%or%-Ma*EX|+cdds2PW z$ea$BYoeIc^0i?1S9SH54!?C9|Ku`fIV&zUFdjx+nQk$7tniRATz?%nJ>TchOQyf3 zBhjl!Y(Be4YkxH1v&K1FN}b54t8-u;!IL;VX3}?Wgs(a;w&%fV-W;=W>& zJsis_?%0AnnNRMW?VnF*xFx{k)zbEUp22E5j7-dIJRY(AM^xC?BhF9I&dr0f#gdXG zdJRyMqfCD~*m@f~`{uz1+z21gT33M)1sRu}wW7vf3Gu{Gim;B8Rg8<7<)V2rtr^UIaB$PH34g-j92R^9vZ+{D)bcPu z{|TjkR@xrHu}42?`pyneKCyZ~By+?<_i0(QwI~o)gBd=dF2AnYq89yXA`Oz>q=@B~ z1`}|(;;59fR%3)Y&D(wNftc|9rRg$-tzRclDFouahJ&T9MF*H5+jK6w&`H_u!>i)S z^Q}qJns@fFCgW+E&Y^{)AA4}zIEKG@g@opXR5_!V4*bz%muoP<*R!BoQeNZ(wvrRr zj%(SurJj&>AaKUr_U3e}-f~gkWT&XzZQI2ZOd6lB&X`#WM*TxPt92-?zE#;$gxDQ#YgRSVb-mo50=xgJOhJmHX>;-91{*yty5Z*(cpBR#4K|*}cueC%)Ls ztcuHj>p~XM}F(D@`km5dk_K^r}~rJcp;Htz~0R#8p<^ac4YR=0x8CpBDP)c!%IdJ z?TyReO$Gz5{PT9&fD~5}l_05OYN0kQ=5=(s#07L5vT{{l<*ABMciIca9p9r3EMGCdrBW=NCS{hQGU$MZ;4#L{=rCGzY5noX@Ga+#Y!1(Qt zv!Gf5pnqx3Dm5U!duozjHT&>BGGP$ie&y{Tgd%G}%c*N<dW7unGHcw-kn~jPvXz~otD@x-9?@2RjxAla zyPtnUdw!IvpNjjZ3jJ3m;sNxxy6OgNIrtw;#M0kPgimqJHK*MY9Jxem$;Z>fMa&RX zHNKir;sI_2zdzf6{ugOq84%^RHLOTWgCISGAgy$R0)nKpG$@_YC8Z!pH`3h=L#HCr zT{4tXLk-<9@I74N-uu4yoO6%w_iysqYp>d?_FAfsoU3_MN-RMn8g{xwSlqAPb<&Ab zca<3|sJ(La6gP>zfV(}8)SxJ_D>G;#Y(EiqNLu@ej7d7WBw-I={Kxm=Fuad?!GJ|m z*#Td`=5<-gn~#1_)8i`zT+b`(^opOxxSvh_5wS~|_Psrnl_X#4r)v_QqtsG#X+mrF zJD}mjN_30q1@rd)Cw-@7lB%_LaYus7yo4Q=B6UL)s1a;>O+K@Co-s^4WhaZAU)*0i z&{|pNOo%!w^IRNkeo^6qTXz=~YDSAp{p1nzbEg1>Zq$0=k#Az}5O-9S`!vch4mSjP z*9Y@Gm+(ZE-%={CzW$}C=<3f}>+Y(%U}NVDMny3km_{A-`n_2Rcv4JlpR@mH=5^AL zhd^S4=+T7?f&}~Rf&)|KLM)G4Xt4n>p!b_9G{}QZrw*$GKX=bSvt71G{7dE;SR;@f ze;k(zPccm#^&En_5&;Jit^vbeBxDQ{;+o&r$p(D&#v|pi9z!B*X)!vGs*3`g2wMd# zEWbMYbNCsyL5KYN)8xhp;iiVq-WSO4_&mAQOO(`Y>j~j6xJZ+Kw0OeNQLreuzlf_* z)EFuU@)h$z-r;;)#~=|LUYTZ6XT)Z?Z@>xMAA1AbO^|Sv+_+1=;%q(F*^=4IApYtS zsI_Qw*ouFZXIG?ANn+Uj$!CC#EGy<&Yy?`w=g>Xh_##6T464sd7N2WYzTrFhC2 zs1o35blFiFGx>GS7YHJ-P!IT~9ujW5nZL z&98-n)yWGz0pCd44`0*ww{ji|+`-?py(r4}uC7R8p3IR-Gaboiql^^NGTu(IB-@ry zGw28v4~WLiIWG-t{h3LBY*YR!_|}Ifm>KLI=f`OM?2)*hYKy&QWP+UuO@1FR7?vx! z7}$-2?=!!Af%n*>HWZ?-bHDX=DqmN@NbN08%D(sp9OM3kfeEpO{TJJ;tu%Ciw>A5) z=@X5320xduWScK{Pb`bYu_6hUKNh7Qg%HX%qc-V#OZ_)!eCaTyx`Ll|NqJkd#T*#K z(|QCa#W&3DobU-tcBnMJCH^Ebp?^+~ni#%8e z1ng@@cAD&t2U*8RGARF69WVAxshY5QsFU=+)$#gWm#QH-1C?XxBN0hzNXKG|%Y(*@ zNR)yIn(dUd=+p){Q4gR8d2~Rm9B$mtWvABRri_-H`zS$>f5HHWR5Uul={T*%$44FL z){UNKQP_?wwtA5cKJF=(L6MnZuJ#{~hriese%WNspv~)yJlpKi1_c_4-zH#EMDLC* zL(iTXT@@aYjHi#kE3dM z3iR&sSMjLzl_OE%CHIlJ1BoX+I{HQWx3BS-LQD!MVogI!i*n;_>O3bYB+e2V6)askJzZ2V$sO z9!2(s>Yxxr&Qp4QHRzVc2TAN2K4Wrs>H83siy5)UVJwAmuRCUOE!5G1l%Ns376yd; z-{G~RixosO+#2%+26iJmPdY~91C>ym4;4_)6Ht9W;Cz%{Bwf)l0=H z31L+_Dn?))uzdR=kY%(|Qx^4~A)lJyFiOIC`W2|J{#vb2+q~tnXJ}Ho z11iE`?kqtCprr;SaK~4v-L6Nu)u#;#(mBN_s2{uvyL{z}SXtrhjfwIr)6R*$Gn%Is zk)Pjw2cy2+4QA|eI4vqIftS)S_0Uhy2mV+B$a$&}NsdXV=z&$;c6Pbc5s3E2@-_S- zc;-cy0*!82@kcDPXx?r(BwLgKGfe>b>MST{IRC|_q0D;utj{377ry*J!m75QMdnP2i%V?x% zLu$t#o3f-L-sM+kV;z7EsKf##ET0DkQ*L2PeQFgIC)o3c0!`ceqsZIIt{M!Ij1{u0 zw##lWoM98v{>0jtA;q{VHqdExoPKCJ!?;-Yf$!ZX_5dRw(^Z}d^yRtgKtTD9n+^Fv zPXvv?Ib~&b7;p(>R=CoYw3%6tpHe#dVNUc?aO_6ycQ34H1|6l%FP+JI1n=m%S0d|zH3Rr&?kJ%rc?Lpaq`%E~@I8e6(^Cv)`(N9)KBx)t-Dx3JWo|-_B$Z+VPK%}Ki z^qX6Uo!Ih8f|$nwDtQU7K=BbY$U*r)Y59N6!{W%{mJ#`Tx=%`SHU)#N{#E-CAbwr@ zA=UW&4TBZfrAW*q7zialHkrQva#T+0f^q)EcpeOhv*7SpPn!a_0wPBV!d7u`%D$}# zg72;5RavegY%bD6m;nmRCA1zq>UXTT|H?reZ?#XW=I3(Xlyo9+fJ+PQ<_~K`5d-%L z9ZcsS4k({z8VmAih|u4tuz82u4o zL9ZWPDG&OKRu#4+om|HLz51YXX`u%)LlcDd0d=zEwjoy?ImH!+Z02hXWc|3lDjou8 zeWafk^mLa1zDVOqC4R(4om@*Qpf2u(h-RmaFzl$6GWwKwq|uos}K@JdMH#+($rik5ov|q; z`Ae;$iCVd%J&4mZOD$qAftz@3thl{FOAJT5#uJ}6j0-Uz$3h!O&>B(p>Xjkp3~b}~ zoxA*;R+M;-9OG|zSJh*yp{hg0D)h6;59l!d(gdms@=G%j}^&B60%gEmoL99 zjwkv@?^Am!vov)!dYS_n%Mm&i=BM;;Bd+jI$zLMi1ha~C_*iWQOpOISdh`C1S~kwd z7-0H_ACRuqs*(hYBzIu=`=a4L-1FnYryyl7vVgcHu~>B`)@*)xNaS3pCEGt*`nK`g zo;MaGRPlMh+p|p}hb@jI8#Gw?gFTan<^~Xt4^@K0uI$sVZZj_WN=M|~XTU?=|Fp7s z7s^I5+9A<&_`T2_C9exL*R6|WYJaUt>j!_AjH1UxBE1e|G>}~0S4zk?Z&O|DR!pz_ zWA^(wk->veAkXuMKDX|yCGlH*2iz3Cx>xq5Ji}EM3bj2ONgI=uK4D=*v{E?rTjKEq z8d*{X+lMKHSABngwu5S(9UsgP`atJG0){K5G>#T>JlQJ?u-jGUYU>@( z=b?NM-$ZVtuD0Oa3Yf)cC!^szs%kw!FS7ZsAB)%AQu6((&4`{#WBe+2QanJD`#Ay~ z7_2VNe6IDfS2foOvsLtd9tmq?;~Wqrv!%{9#g}Y+22_U3w=>1bKP`Is?RL8+c%##5 zkXeJBV`&G6^hL9DDCv;QOE@&gUYYe9rcmk3JbUf{^Ssq2{`|p5_h=Db3YUqJVu_w z7{{!EVeC>TW|!QmUl6MDU%G=`rE|*Muj4faM?}Hg|E4w+Z))JXYWm01$RAnOR+_8Q zj)o8m$*Sh6-v_GN!ZcZG(CD#+pa&!L*o^Yy?b0eQ_@Mj0;>J?kRUSfIJcPOVR;>L89y2H}Y!~`;{ zayPa8`B#RLXRe#m5{m8QAITdWe06!9_neH;B6wGTwj;pZFvjIkuv)yB;hQkOPw2p{ zAt5TgX2A^pX-PX{o)0)NMrw~AP^J$)bW2luEtK=@dx@j+GAKuZmO`lij`eh7+tdVd zFTPltgSe5zrIE!;hfA5@#cf?Kl!7I|+Qvg)>?tmoAOvbho#d@f+WfT$}0CjPO9^HIP-cb0jPR8@@K6gbA0)%LHgwaNe5M z&`0G1vPf5@GRRmfm{B<{Bz)zW3-*^6O(6H`qFsjq!2;b(lI~N?MAd_g!EAeXicu<^ zdT>S{Wig-L*ewn}q`Pr%rk7abSjp7+ie4vHanA}Ik_SV<)-!ZE!&LLbe)&$BuY!{R zhingeg22exy*iZH@uP>J@BKTc?y)2?fqo-enmf#D`MBwFF8fjeN)%Y9od^U)23cL% z8*Z;b1bjc?@xVN3)3E|#&OALyYjpJ#OR3k#;imr8Q*e~9U=pAqTEAtDS~#;AUM6>u zDAzh}FlRu%M`F$(IKrwVX3NqGRoL)Yj%%jPk12FdA}dZpM$P^Vwa~H{iy`)^EBHNZ zFLB*}gNQ|<9>#+?OE~ksD z_MaAi_S_R(DmUFaS{tVTYNKxpR}$_3X}WGy#S6f4L04||Y#)tM&XL7J+Jgq+J!I8u zLN3*7@ypt1cw|LV#bN;a5RUVaf!R>1`~ygWIvx*-W)(=pgGDQy=Xpo~;gdZO0j^r9 z>qp0cB=j)A0IhGYOxKZnRX~jSfNKdi=J#gvaj`?UF zW6r41bs(;7sz9|Eqtck5c=hn_RG-QOm{w8WuQ=!fFFbx2AD&K zQYvG?0dU|tcv1XWcZ|gkn84JE2D@$|(6rX}sd2-h&Pg>9%O|9z?ijUXgh*<*MtG9M zg^cPzM>+nijA`PL(U#w*$FB>%Df;|Du;%vTQ(5N`Jtnj=~=)J}p6xAN74*VV)M_2XsAb1?&P4ZlVAX zZD)+3W6IUZjXVgQfoyAeXr9EK6P@LWJbR( z_sglHtqq}FyykNIzA4~il#!Ap9thajV7GxRLrXs}?_%%vbo|^c1WNlYzPXcRnLaApOZ!05g^|7; z0iorf)OL%B5~95$+Wr(*;b)T0SfCAuk}X`2Xj%$_8O*kZ1azMXm@1_?kV6Vl(+tyY z;wDce{Fx2TdCn8Rbr9i1++q)vKe$|zF5m0>`qd>kBm_PlvfysT=D!drS^twC?yfz( zDDqfX*F)}NqhAyy-`>dRfi(eDacF1&m}XF309mLI4)%O*P&VZUpa0VKDItMb*M#25 zL(WspU2ngUYjKnRD2PwWBDwEXP07V8`n9fCSk+Ehv+$xr7doBHNk( z4z)y9@6p0T+Qc|wbxkFPMbdtS3yjDT6299A`pN{ZW8yFR`u`9`|CrzA5I z3NW>(o7H94)TI_Clh;W$(ZVVZkEz2&kKQ+b!nvU+KL3Ac% z9oO^iPW#@J4P7l$Ej=m@NYwk*Z3M*s@gmIup>BFGRfaq}Q4|UP*DvIV9ErdkS?hnn3kHj_^6W#EBxMw;KLdPu^|d4JFJM_mN^ucTh>lkvGkMlN zF55X+xqh#Rvg35~U^83Txi6aVuD7o#*-BF3xI7G4J)jpst?pZTMVq%~Mn=d>n@-2> zlikl-+D{16(bNsqYdq5}Di#Wj7#e!z{8^c+CZY!oE`ej0hbr!d^F6H90Ev2JbH!^1 zw)GY0IbC3M3H3VX?N1eGNTvG!*+DHo2j%*DB8tsQxMrRT|H8)T3e`c0)-~Nk-O*o) zRYMy|xd2K=wkpiI@(@xmi=#_;9xxG+R4W@oh)HKPYe3f3x(tCMb^d)IPt>@#ZHkvA@6^NYEI-H;rt~ ztU9O_K1+MvG}e*`r3;hLQ^>x+w1~KdQdD0Z08__I5cs=KHLlAR9DBZhreSO+h1XWF zzxfRvG72&l=SB9?Qmva6|K@CRVKoOkKS?g#8fmrQ3m>kO>A4AfF-dG=rPpy-Hi|xB zBF$u%#|k1vp_>Dj8^y=(=PsK*gg97R3tyc0Uy|Itd$%2{tZip`LNCn5bB}ara&odv zm`nCgw%5%X-h&CR8&y0!Q4#rt)M)jR`L5p#?)*3Yl~QGdrn{MYY*zDNJy z5|m_DD1KgLYj3gNOV|C{{$lQux{Kz`PYL&}wNW(bZs_Qe6> z6ax(1_0`7L!<{LG=*1{7)8Y?NJ-{i+qP@oy_2=;aNV`^sCMn~YsX|Nd#}LGgnYEa(L87GN^qcY5D2#8@xQeT5%+}0BUkCMV_77CpA4;SBQ{`(R zjE8IC316u~Q9P;i&XW_Aoj0xw<7(=Kx4ZfjM2hFLw)NH3A1G~?mzJ`fo}mPK!LxnV zS5_WA4U;VR+_7I1xVia?St4!ZueiYDnhPLD(vR$Zp-I2=7aBJmKaflQ&rSZt{%^k0 zKwq>I^I~;0i$N${k-+l3-@cJAn_6()}^*o3|TG2Y8Pv>ES zTF9qA=a4@Jo#nw5ooreJ$Q95hdGz@3$;nwHEFb*>NAxb5AOj(@&7~dxu-#Ih`ara~ zAwooU0&DxtiFC8g{|bKV2tpkqwbw;q{L8uT!KFI9cfm=hbHdnvgE|fT>LGrKPe#M=LK^y zfy6ZqYFo7>Hetw>HIhl6J7e%C&;nE3w@Z0O;UaiwVs}T^dh5gFX@KL{z^Z6>f zhurl#olk#sAJo-4dokqDg|;tt{bV+WSl}W=xX0L$UGMvksq#nYG-L>u0ogfP3C+Ua zRGaTt-ObHx7>>z~%lL&3pTm1Djm@}Q+Kq}xE(c3pE3o`%bTLqc%1HLh>jU`j^M(s> z6p0!Ztnbnvz1sX-p+lXTLaTReVrigS!mwP=zl$b$c`^qjm@_;DRS>dt{5D63Iw9}@ zW(aFU3$xS5w@MF_kl=eQhXzgi1_ZRR8!uu;?x?gd)L_w)jNYp=9PK2r6Ua5Ef}+|Z7XL!XsGB|#O@ zBRQtOjkNE0oh&%OHCy=Y_>2yPj z3e3iQ{-taRnYHv>$ci|q0=EEibM*b~9s1;;E#421eXk%Oq08hH_;&XakKsNa`zX;J z_zWORfuW%}xT`lP#rL6a|MJ@7HBGEKMF+fHa_UJZc*7_rsBaoeY}mrk7T_feGSEox|`8+v0ZM5~H| zDvCIAt$!P+Jakm?dYl^t2%`ewOj7JwM*l8ErW(LjVv{xR+^E*K@}i(!d$Q)gt6~4C zy?iRrP{m`dzKzOUOW*fYZ_&kz>7*N7`}dz1kBTa8%#PcA^AFCK0G2+tCR`tLH=F+N zd-eGSV2OKNef|2UKH7+g)b{acj=#%z-mT5RKabj%X|D+d7@@#X!DEDeL&?AWM4tfw zCQr3C=nYKc_izF%XX?1vf0qZqegHFR$yPqO(YQ}R!xDcWHGi%R|MBB&LYx5RgMEgS z>rwm&VM7xoN~Z2{i7{=dLo1$iYoJ$ZwUUMEb)h*bgF~=sOK)frBaytAVm0gm)hS@ zX9SSXby*f14U-pr*KWrjKH(48JG=@&>-b0}@6EHWC_V1V@5O2V!1K+HiPOiT%EI4< zQ~~5i)#CLt#KmH5I-StOzf){!g72DR(##MLBIGj1asMU<{R>N+PXPq}o3XG+55kF` zOUk=G=Ko-Kf2JVJac}~PZug|$2nrs+5wR}2(el4Z@!JT1U0Z^1gFAQBbIMz{Ze3n3 zFJa`}bj976L7T=LyKLPleafWitCGj87|kMn_7t7r-Xu*{bQT_5)9|@3L2)eY#}`i0 zxEdArs14O)yVbhX2E3XVL>79d4_s5u9v$uQl@d7v^$Hv&v-YV1&dVuVNz7U`Fsbs$ zq*S&rTKiM$)n^SS>T!&pdK;ch;fmh+%i-;R@~skssMoH_J4LdaKT9e3Fe8f7twv-{ z{?(}HTYo-Cy871bh(_F-Ir2XEV&2}J_zS$1asQ|1iRRn`f!IeVG@USRK-@;f0b0@M zBj3FLy`6(55m5tVt7)FO-=NF~jD~{~&&@Ob^iPmp}Z8TF%YBeGpL%%hx&+ z4h;F=qn42iy~;~T+POXXxrQ>LeV_B*d3WlQp=kR21vmW#(}X|s0ilSSgBIDQjyfqD zF69?y%SmqdGF;flet=($wKI`P8Sxn&PJHtbf(6Z=&p!Vv5Xek?(vZb3s`uC?%a*X6 zX*;J)QW;F3f^z-5LJfvJ391z*!?S1?VusDfRrRZ zXxoHf#aU{_&P1{kjEH_mDgsg5c#zcB{QtPy&=ApZ z1nMJ7UfLctI3vS&2|k9aWvGbOlV4)sbBvgj*2%246WP9d#aux)?YCm6LF}R^?{h$Z zwUIyHf0iyt>UM+$51iF&<3h_W)gwpSZm2GQj(Gf^GR*!$e`Z-^@kqz3tIi~uDvq!- z*+;AUQvq5)?|pT1iQkjZ8}jo$LwJG~FgipPr*o(aYx9y~(pyVepuGzk3< zBZ!s-WOkulF)CN*!r0G@@;^t~U*g)+Ck;`&M6*Wc@VrVdkU&tOzu&RGCBFBcLg|C^ zy~-rDX!1C5k$+Ex!Rh&|D41dP84eC{DZ$ds?r-q)Pb&QN7YGbE(cYa8n5sL|+b+9R z+u6c5CM%GK1D{ddumuV>dF+<@1@&Y_3UjuM_9vh?=l_43tS{>om5RQ_uxY%gFx;t$ zbiE-C=sutvh+>g?xC1?P81xGCACcTMVL}ZE#t(e;f5hu&0#s>H!xs?T-c0erYixj| z5V}sA{Jc9sO+lu2Z?wV9mjB*Dq6J9rhSNnJ!lbxBOxKicMWYWdn$toJ5d1k?u<_{s z^x*J1#9z`QiEHRa>n=0YNM567S-Z+ynYHN*~ z_z%ecrr_X+wlbxC4#qFKuujLlZtzX z_UFh6t!qse^UpHK%&Bl(S970Y6TD2Cb{GjkvyqHrompHb=770v)fdKsU4f~eHBbEh zox8)Q5iG{fnepl6Vk?ZKWnvg(9>~Np`+QGNt7amRXRqdiT#&6BQT9QoDLwXrNN*8a zon3fKzN5-CD+kQYcc5)pjlJRLcYaDur!Xb3X#|LqVFXO|ko@%haHy=k{v_@-*qx7j z4B@j+MGZeRJ$R>M+v6M?ILm3Lv|ix1IQHQ|l7=q8cs{=9E0|>Ph{Xg8#s^?sMzKHQ z0}ux)#{KQ;#_d-o?&@~XewHAjzPJ&20T#mvPq<^DVV_&YA~281P(zS-Z@Djygv+8q z!ek(Usy*y+)`2I*+>{OLS4FQW2_;T>m5X}XG;X<%QZQC7sJ7VDDzp~wuH|iV+})o?v4PFz-L7tGW-peW)>Ufjx?e!% zp^#FN{o}swr3Hp_yCByDenXA=OR^PwolSf__E997XELH! zOe317!e94O_QFxYK2h`p%V>o^)S{% zKp4upK3g25?Jy* zIIuWZ>>`kMI`LZA{;uUzwT^TwBW%;KW#UY#$xTu~eDxhLMz%YM%`qZ`ln1iJ+O&_i zI)1QJmMLXEXy}hczSI(Zxwz8-kviF3nyz=uc+&Qb-Eob`DP^|w%yJ_)WvTZ{$E@N? zeRbV-LB!s7sfycQ8=IOvC@f`V!>50nLh%9r)y(79!cmW3cRdAL(N}P`T1R_K=wuOpc=j}o%R)`zgwji! zif7s-DDh}GXg~&-@HBk_mc=0D)^>u;T9vxB9ZWp$id4_4PcVhKEk<-0F6Plpa8;R) zMIX(%3ydA)8u_(cUT7g>pNJ|cg%;_wcna}BH!5ceGO8w7zKRF5dgqg7O?~3ZcoKqS zmr7U4`H+gMn*z-jgMp0hy?*DThlW(%-Ykz?yH(6a^YSG#jr&O0x8cr$t{*=Q`JcJgLgl7^Fv_LBk4cI(8*Iw|GW~}?Wo$P~ zjha2_c3BsF%&|uF$eJqBN-xh{s(80j-2bMe6Q=HAKLEE zE&{iM>5t|vy?Z~MghaD?#E=gzcx_K*vvW8yfU#MOX@_Z5XV_ujK5S}$wG^5JlmWIku_9fm zr(VWw^MQ$tTkc+Z@A>SP123k^;c*x<2ct>;RaEzw)WUyKV#WX&dKbvS{>T8t$Mf{o zJxn~lqiLGV9ar@1SKl@iMsl6m%m#n>s1$jCO|zWHOT9Z)3)N&|ENtG8@8z)u9OzLios!O~?O>=s^~b+7Dp@8xdHf z+(oGr9~??a3!7GFMG+W*Aj<6k6~NPumv2Q2*hdk5)~&$leJLntx7ZPRuo$)Ul!V+w^ZQAzs-$Msn@oBj3I#*-s%GjA%Ytf`f#2P}RkwN2)UCE!{fswvmCe z+Q54^VOhh#dpN6>LH52h5#J|%sdv0W8LJzaAx4TkaKC#yB7SG)Q@028L-rVb+`vn) zdCd9ImRCwPAo_$&wPVpDmnXYB+cYD_>428+Ud>IlHh%0uhIlT5VTymHW=~EF*%rYg z@_XO_Zz*ia&R~)IyOrgc*-}F^3i%WC<}<2i6au1=X`MLy?Em3Qfbda|w>YwM@0ip5 zkgC^_GL)Qgaq`@pc2%kzpRpcF7encRjTO}I@u$;-u5{Ay%(}b}J~ymw+E~^q=pN4Q zSzJ!E!NZIk-QOFq$R6gJfQ-yEI7R@6Cpfnae&jOcl(D5McN%?~I#DG1(ggZuiU#{O zqCA<8cnS*sDx+BCAVT zT#^ARjsR!x^oHWO#$87+1>ep_MUbJV@pPv_geYjg{4MNN`a-% zD2Y=2NqjWbOxmK0%YBJPLm3Y$Tzd!^^h%1N8I+#^t(h?c&c2y1SQmyQ0CO#wA4rp} zPU)MxyoB%el&T2@ZD_y*?AD8G0$ziiVEn7&P5#O%^^NC|Kw@5aeeOi5`7K{fk}@bM zn{}$rKDRdoUTj&;d?|CHz}o5Mqf(%vxVyAhZ=nGTdu+cfn;fky&!<|T)-;Ayt6lyo zd*#6BP`RRK>4CHqpG7K-NAA#JVI76Yj6WG)e{>LQ;|mAz!G$reeBitq_Shil0<4== z#TN1J`kgyL)j`N|<{~wbNOs+e^7p1e9WOtJk2Ung33M;UggW~Rb9R1P6ajpNeS}P5 za+YGP8r!2v{m<_X>z;8~*Iw`wbFFoHu-AxwLTfszUOd}^*^4zdx@G~L0uI|cD>R^- z^sw*cVgSb2+(IdZ+=`;C!fJ~+)U|E>wC%duQwHq&N_F9f;r7+biBp1m!5oWE*Y{5A z*9&~%jq+dlsAugPt64f3ei^GEN+!sMYcu@wwX1-<0Jopkdh){X8yP}V{>;c}?sK*b zBGyl&6;w^P#_t-)K~vmIJl+rKnaR1_Mt?LlP}*% zR#b7&oW;_7(A~OqiG)GYv7k8S2w=OL{6JtM8As%3zYe3nxdrNz{_DQ*QCI-PQFVBfQn!_`X8yP8*vMJTl0t&Gm# zKZ|OCF{be%mjXkg(?P|Qg!|vX&0f^m@NwmZgN_d&iQGM(@1PVV!n2pUnPmJB-JfZS z%$~pb9A0O)6fNk=R#rGjZ(vURj(XusP!3IPo$vtK;EHboDq@7TT-8b`DY+A+aAt&r?#a zLAi4F{rTwHS0g8J?)8yX+l6m{Jur}PP^GO_^r_|k9-tTjpB&GYVn0>u3ljF%Gd{8{ zXajLT#ClQXhA8ID2{=Xl{Ecy%nA18>v(os<%R8+5M<9;&DP4PV6UcerPLh4U?H#S8 zrPH;`zH;-isf{_ZWcJguk)%5NC3U9bg)NV>4U}eGjRKYLxc)Rq;t9r@HnpKmdK$M` zfwAOqO_PNs^-Aaj4}Wle_81$A0$RS%Xn9Uj^Y!-{pf~|H7C0^G4NS5@$S%BA3-5S zps%}kK(Q`#G!12&?{{9?F9LfshI~qe*1u^x<+A&5Z+j)nbZT^9eRD<^i+F6fh=T6W5izd|5^%aTzhpT6VVep5b0< za*W+G_{Yr_O74y4?tVq_!wX}&40Qtna~JB>+U;f3<8m)+f*qClt_%yRB?^!IopAQ? zFkkBw>$ZB3T>g=$m_o|(x|7$bnW|KBg2BvNx%{~_#ZLbES)+EDoR4r^4*StM<*)oq>h6Un*p2knxOSTgohpRwpisVDVb~Ih)x30^m?NmT zIJ<)~xqh%Z#by{kezp`hB6Psd0R#c6Yu3S^-&)OG#7B$yWARCh9GJtUQtTGwYI2g| z=)Jlzd1fOs_T+~J;ZRzg93xJJiN`(sMlOF4%8gWP^-5(JZi>Ss<#yTJ5rpJeb#87> z)v#q7w9%#5^*50>QSR?_&^#TtWv5d}A=ya@A3p*5O!G^?CbVoCW@hB$N@j$59G07o zQ0jVQbTq!{P=MXF^gM*xta4`;!2G9>BYtuo=)pz(fpQU6=BDS%&%T>(^2B>%B-y56$9-MB)V9z*$N)}j%~Z}=rNzW%G@w`OtURh0><@v9ZjGDE zR**(MZLSnSme-r9W44gWB;qUku^8baFZSsG%ju+b&gfgLjX_1XMtc3_yiakxh9X#>S%}>%Bw&6s_oN}qQ*U)R zJF%hHEOk#aw;z6Z(oyt?f4#yUR|(ms-)(<&25${-AVCxgagyF-GnWYEmBOOKLZ)JjW7K?_55_OvTuLs{v@cr>)bk{he^Fo_?1>sgy_tH!_(3*_HXVC;D=@K8DAfysGCuj(nFV>#}`()KyRylf)+;n9^RmX<(YX zj*m_^q0TpmR~9pkI5K@6HxA2A7(x8{z9oB|G7^L8BNGrL&NAdt>LQ_;Z>LR5^6QXT z^^TdU0TEJ`32poR=WoZc!9KpEM zj>+pbwR}1K-nVT!n;bXGdrrcP@|7M)NS|2WeP32$F|T@@KN8+$_QV3it5YlI}VVkpHfsU7URhf;s!famr6*3sJD_C)M0m$gs@Zr2e`Rl}hkpDH zWMc{Ntnhaoj^8k?t)vs_I+Qo$=`>XDTKebCxY7Y$hz}T@c3yBrq~;Tia`vG;@9coH zyV(4LDwyrkRDKOjvF4PVN7 zkAnTYyyvNx{pgYvh5OTI!N*@2NDft71Y{F<`^l?lbvZ7j=r!x^F)v!To%hLd=xrV4 zy!;%$x%&pc$?Y)wTL@`=5VsY?FoaHRC^?MtvFVQnrOa>15rk1;z(J9v1sazMzrdwb z))H2`qij!6jW8@Bspc?TkQzJXftiu)Ps(M!78;rje|V|^$G9@>$Hfd5<4ySM;hGel zwb>4yt4JDkcG(-pFz0dv#N@u0G?qe(p&3g_xxMy*$}iSi05PG}8ZX-I%q(7t-k4k< zp&HiEn|e`VNqlkwtr~{Ms3%*Vsh)Weu)fU~N*=fPS!WNObWEgCJcR8fI3_!$FLuW( zJ0LEa#sU_&RfyW;H>VEyyVCVSN=d}#5~I>VKpJ@-&VV;6pO z6?{ur$~oCG zR0(#^9jCfVS>2QGBnLyOU`nkesBzD?xr>NvH+hgHqo=?*kxhnYGY0S*An+-0s#ccD z0Aw7|LW`@&3KP4sSZX~2KyMe@Bhzi1Gr^^eu3<{To)ajvvY*3oWKwp)S8D>9uD3yAp4n6r(X`4oDdDqg^k%HG!KrysZq$`yfRoF~Jn zBy;W()=Ht@V>Ed_)0&Zud^7)3;~f6dI0f7fS%&Bhk}n5UoTEGOtXcw(5sTBne0i_{6W`7@e{A=Z z7Z>wEZ0=4SYmJMp=7Sj$L9nF@`mR-c@BQblfHyBsEaYY>z3>g&ZM@Lqs42w_uJCaz z7n?=5@hgSV;9G>0aSLIF8Rh463FX$*E{&e&wtgnFZ|!se4Fgv&aa%8Tww%CC4F-pW z?PbyJnQi?H%@%&%taU`ea5SqvFoI>`LCys>0U}(uqRE0DT#`tG^gk1N3RD|Lgqz)x z`slw|5U-Eqr<^|! z;+n8UYyVZAyxbN7X4@E2*ne42Wv_j4bRN{tsHoTH2&wU+v(zBxla1qZ6exAO)R3gJ zO*t$%@>P!NwbDv%P^x4!x(fFN{NvpB;u#unqW_nQkpeVjYKvP+kfZL<;o6pCKmVyY zQfY252^WNd@2lX}8ao{JT)7ceb@%LI?{fM3&q?_dyt(6Nj2gA35lz}&?wnKkEsm>F zBYRLUBD;&BA--gS(s;h%kCi2LLO?sUmdV#)A`!2UlCpXec|;^6N4O_A=7_c$_fkwI z{V6@8GoUU)3WW`oDJN%1BZU7*n~0--B|%e?#N@uzz#hOl6L8CNdsW571^vm_-29M9 ztpr>c=0GvNjtAXS(R1X~yedvpew(Qa2(xXQF=tYw4;xpxNlr6c-pb5bRgC1Vzs1z z=6yVr4Ziu4_L8gAlZRb0aa?hrmpdM6T`3Y2I%}50W#K75v{yng0c5MPd1*c*7~u)Q z`vT`?A}DD>AS==N<3=SWdpn^RW+hougNk&HSyIJuKx&LW)cZuk%Os>>ntWmi+BYBz zXXcFZ64$?M67ahGvO3aYr#@jHqFj@L0`IzX-PGneshI>iRt^*-a@#nqkDWSxHK9LQ z4?ZG`NU?9MgrzlI%c*IH|KUwya{J0M2m&(cjXcUYn)_`Zgi_KvZSU3~rE5H&_~3#- z?U>8&yg9F%r>Vepu#t-_#ZS~x-&+^4+G1N^RBbKfmIO}H#SvIvv&gz@0*@G!Jp&Xh zBE-x;zc=Lz{E@!Xu2KtNlbLXc-whZgec&cowKwGZF-p+#f^?vNXPZ){Dc)*Uo7=|M zLI7+Z6Se=L-Zi+GewjZ=N!PtNtU=bMXay6WV-*{-zrJ4ErXZKQ9Umj#@fmu+s1c$> z0m84;)xXOidyr`DnQX)%ixSG{zQfzcTWG6IsgCR8?%X!W5(&2{jXTmt9S|@f|M1Lh z!!sO5R!MBI8b5-^*zrYg9c+ zqS7f^3Klw5fA+;7Wpu{o1NOAbl`b0si z7sc|M#qv3YarM}wjR)5qYB>&Afj1%YtD6@i3_`aHw=rF>6Zi;h(Lvall_$0d4jB-<@~3sD#v z(1hn=*V-y+-l2w1O*gs*DQBM*Oc=>GaC*-^U*(g`Iw0G!6fiCQm3v2o9S>4m=Xg+4 zL@PXPs6gy4TiK#usXNqrBAk8X44(RoF)qlrnjpcFm++fL57Da{KtZ zyeeztlh2YRHVcIx&uXaa9ek*!yNuGUu{>$ViXG)o_FBfySzZaSUW&J*p2og&N>g6X z|H19Owv8pg=olRtBIfIln_8?rYFLYv1s<90Qua)oHLd19OKpaNpXhOU56Yg>)K^Y7 z+5!i}+4)_zx{h(aZ~XJ#l_||@0g?G~r)}Vim-cNTHNN1UqMnl{9lad6eQ8o2=yd5kgo+~B|QNyQvWb1n~7+(VjafodOeMAO7yRPI^Ql1vf-AS^qs0*uSR&%eCtpx)~ zu+6$B1Gqqt*@kFj?>(_MF%znu7tK_)Rie-ruzkspIyqnW^PPm%oqhUBd3w;WO%9YB z%EJOxm8`QHSEZpxVrgwNBPvA&y_rW7M>mvJ@njwXQcoSB@aZeoR-^Bvfw&%r@SM4i zKNg8frCd~Pal_e@3YD}(0sWrXCaz( z`PK?~kQX+#S2m*SF?Q>@+=a#Ln+eZlK0V55811DHYNaRaEFD`}0ruW0seWWvGsEib z?Ff>^l`J5rJK>OUPhB+2I`K+fe-KS=h6|?VLTr=C}#1b>M5e|k^3Vq#%_#kYM{ z2@`_L)m*3}=NOkj+6UJDi*IeJnWRRp`F8dD;7x84HRqadKW*hMKngGg4qe|-1&Lh5 zK%Z-MRM|eS-T|1`vBp6~6#7(^?Gcw5PI6RkDI}u(`9)&W>7tO=u1LFSXL!03?%tQl zB9Yx*{6-$mgAGXz#Ii4|Btu#42v?`wnkeNR8Ub75ReQa zS&5QC$*GiFARr<+hXRTy(h5q>86;1TW+(HijX$iX_oC2-I^Ee(ymu{Hb%3S zn#N`tJ*NAiG&X}H;(YOc-q?_wg5hH!y zbW%4=>0~Qjw7dCTIr6BhVQr6b87#4xe)$q2jIHU&(Y>>rI(1u= zsYMimbe09Q&b@g;O#N%0`tT*#IVBY-q8}Gpm;sYl^`@^hzPM~Y3)yqa-d4(6cHT|G z8Ruk0h^^vh8V}t^cvrt7Er(Ic{f`NIZmc$tAw{i6t`+HTOt#1a4PRDd^h;(!Np!%7`i-Mg8^1ubE^hM6FPp{gq~H+fd+y9f{yPrM~` z_z5rfRKxZoifMJ~7av&FYdg_-6Z;he(g~A8RsKp&OWm-^taYd2jRB_+`BfqDCx%vo68)l8_+gubmx=}x<)Vdq9pzq&o}}fm3hOel+Ti5@f?|%3 z2>DlcKb=SdAz}DZXh~hSPr0^T+(D%H`Y;YNLiP`GZ8akdcNP*&KB`!?#doKqWAEOz z95N3b%?K4o#S5Ngz#%h(7Hmm5k+I=t!hP1JkQN!`J?16fW*)u~Mr{Hfo~7Q9-zg;d zPfhh(5MOgl{L%W`p)>qN)P^posl{5BOlsbbV^)veQU8G+|l+!y5W8vz&L2sD(R zc&rE8&eU%-Fym_JYmDOI0-<6?h*ZEc;4%N|VHY z>Q;ykXUk)TH%agCO^oLsNPW~-esR7mEtPl+OV z9A?jXhShk6#2r118mLe(*1yF&tyNj41Cgxm65Dyi3kXameZpYdldq=Px)>ZEA-afX zX>08$a6oon94ls8yU*tEHQH(+h_}}s0sF}3z8GCRu-1}|+6v@mU7?8-Z}d>`BOtEn z>b^K_H$9U6DsZtLpXd{%RO=ItYV86x0MhR+yh_Y_TwVprMbI@XwuZ)w!aZxAr8ICi z?Wxh^&H@SruX`qpxaRGYW_^g~;rgw9V_y5Y`ZDWrNB9BKY@G*du)&C4ncm22rSz39 zz5|`;Sp}V(3iJM{WHUTaQ^*%cGW7bD_Hs^C4S8Q_JMi3?SSLkJR;M;jW+@pm4`!>D zXWeO`y3egg>uAp} z$#n*9iv_h+|L3y7!uJU28*4e@-ZCH zsWpJEbRF%_jw4270%HSGczZINr;DJCAGfLA)h1csK>kL&3As;%JR~O@-`{kG4mW`g z9H0n>nF%}JV0RlRLKU5{Q%n|io!l-3-yo)m0xwlzrU5>U7PK2@DAE=CUduI625-bQ ze_bfH8+LU|w6h*(5TNRWuOXA3k-Z(^YV;miHD}?}tCQYZ6qyijJmz|`z++Zwe)8r7 zTM{YegAv1Y08{RDi^de)GB@8O=K%%VaS>GEA}SWnS%|Myq-%q2t!d#D@ff+ps#TaP zLYvn!0ojO93alMXnIN-?j6WJZ3Nh1dPP`AZY9+!PjaSseC8a3_Fet0(2 zpj9>DzG`PIH=;1csD#SrP_7tm8?!d;s*_TrFD*RdRY4n7{&>Alt8p^?*qWJWA*v&p zO}=D1V#=@8#2FUL_fyJEPiN+^!JxLH*9o)kCLHPq+x>%0;@ zb`u$IGWJi#Jla0LIHG4)n$xq&(RgJOg9+S$H@TxJOKGg$wwRoEo66VcC8IsiJq*FAS8Xah_g_SCxG;u`}ss!kcZUQ<98w zWeXzt8HUGR%?l%GDYk+RNYrjUo&ch=@howFb-aHxHID(7~ zegq)g?ob*eXRzYgq9UYeWDznFJRXHT#2l9Mu6q`;Ft4a1x!DZ{=9fgzbW+f(rA{Cg zkOe2K-p4t2p;GUwa!zzCg#auTXWRHKMZiS7vfAs=Y)Z3;PSLdy)f>SdR_a4d!3~Jx${msArkQlUgIVoNj|w zqC>TEQ9a6`OugIV0c>SzV@ZUB*VH@Gal;F}=Cc&=r|^TmKv3u zG=knuPj1cn5xH&*HuPbRKS-ruhYsyR{KPxNo|Fk+%>ks%o^tcSrJj_-dR;kDjCN1I ztn;K+8zZFgn1b4<+u{WDiCPQ_F_InV#D{9In**f>RzG&zXOr z1wXR~n5{w=;{A4fZYunn_$*_va`eddTW^8H$+f|1!vKSmW4l_!g1DCfhC^`l@~8pi z+g;uzxL)7cUibq;EaEQKV2(pj?t)W3zueHk2Dj?l=cf1v^=OMm;rzGprU$)J!kwkJ zo5!bWx4VbekYHX)wvH4P{eFTG{=@8}-ATI?CuEA4huYC$pAa_(Ev~Ib=PMn2jv_Bb zr)MYCADxt!8me`-ZWxJ8Car7mFqz9O)rtKCPDuyZs}>qK5{Q|H+o*SBVJkUDOwziWDO zh7}CK%CUL2yWelJRQbNR92gl^th;32w2h577gy3;eV)EMb=InalJ!4W646- zze$nknSZxrN-47IRLwb&z1Zc$M{c&fQ}b$aEu0FrBbzLsUJ*{;V^U|^RqbIoY=44S1F`?i9v1b70FTXb?Tanp35*Fe<+?PfQ<(pYL8qq4zwCLBrn-0Ls* zz5LJqSB0~r3ZyNzde(ci5s`uMPNF-DJ_OxpQOqSOLGQ07Dpo9yPP`O-a>gpe*Vv0N zRY%D$E4+@MySxT4Q9{=dHHFYv=x>%c%pL{y=`dC5R@YkjyT?azYnLf z)s=vZg3LHiU;wV;cdw#BJycaM<3i3d|1j`dTUlCl+?MLqttCjizltpI{?g{8dXI`M zPha;7?bW==uiJ?R+Xk*!l@uGR<6`~#>3l3!wAWv(gP6*(7_jA`eZj}D zO1rSC@zjlTOXeAa+tZ&s$Es`}PFECBr>rjsRarV0s)I(dIvXr0I^An5={bR@tX@p> z=bwn4(lRQ{-C zXqAOkYF9VxC^Z=rdFUbJlh*sh=5Kc4sOFSG7+Sa8^Ifv7UZ0XXb}`c&CT!AerGoH` z257Om-B$y@pBkSF6PsybzwZ)JoR}d(<}5=I69Umi(p@SzZ>>3SrJn+EY@$&rc6g;@ zT_4dk5bQCn0;DBTd^M;CfDm0l)G)ElUn=}=jPwQ=BtZsz; zzPwh=-n>qAH@FP|eM*NFfM4bHh0i_{?mCEUck{}uR(t2V#v=c0qTTWO_D>nO%T&$g zGqLg6l+n7861{bM26|Sb5 zu$*Pk24PxH@$BpwbQGL+&R8o$&GsblPxkbso_NOdz|(QGM-e*=N^C?dP4`(a4>G3q z+rcW1mKF&JLGCDu1PpaiKV7Cwm;W>@U1eFoXU{uapUE6k)s%8i9aUeFGI?})b+nzr zEa_YCs`TddEa{D8i{GjFZpE>y_PTJ&p_}_`h4h>61J!+2&+soRzUeA)zKo6=DsXLn z;*Ml4GynFC0*y4Urr8!xPNXn>)|b+#R?}{RieO3gd>}09v{O@0RQLuWLCr{9?LE|+ zAOMRnpG?ZcFr$y3*Or->bjOA7ZdMCZOa|7wAUQa7`CQ*ll#sG(I&4tQSWc7E08Ue% zBTn=9s}+6|ITex8_su+Yqpn21zL5ct2FhLaBn;6`TI%k->|p!|Is478#clf~T15%Z zU;@#gJQ(OGGi)|2d&E^k*PKXR&}iFofkea=74NfuS2Lj=^Wq_zs=T^W1bx^CgAP$e zj3%8iF{wTV?2NKO&ec?X8+Y5WkT|%A^q%8MXevnA{)v_WhQ>l`%=Wd!^c>2 zO8O_zpsIUA`qYkmw29cg>4Ix-zf(W?;BAkIY($X=Dwo;)$`%XfiTtV-YX55knM-Gt z*LQ`|mnKQjL(P&FxnRm`l|8!lyK8oz32iqES5qlO_q=MiLso2E+?x`0i2GwE^Re}^3GelAk>jD!|Ubpw{-;HBuU@R zWDJiR9U_ok(W2tBUc0C<*kGURawO=1&MqFmra0;}0I1+^XPAJLCNi1hP}Aro4t;GQ2^ zw;taLoN_QzfxIXv_d;meP5217ILqgVn86tgE(R$7$pHJS41ovNl$Nn_0!VDHumy52 zebp8Sk@B?)XwWHN9}@FN_HsAQiQnKTN|wZ8SV_?Dxu-)be!*nZriCGO6#YWW9lMY~ z^n&Yj1GT4+(-&uti6aQ@Q*D4Gy0i`d(!h4W z(2)1dm$h!w6Pgi>a#whj$T)QF0Qd{p!E46%V-~(=Dtaco4yA4A#W`|E!;~LY;e9?{ zU|k7QEx=2sM$~g;8nfuotS3J8Cqcp`YGEB!k##-~hp%TvKdzsJgOpbY|2pa3O_1_h zQr^gI@%p(4hP__E zYF@}+cEd5-8?d|ez4_^rgXi_-tjg7O4)+09E=Py)wGedI3XrDOSH;&ijBlUtZ)68s zO>d{EbE&-#FfKLg zWC-o@_$9sZo6=jp-7N3UetP0)aSxM3(kFT5*lC%CQM`;+6|oG)ZAlwc_xdc+ksOTY z5x@7S-43KDzWEgm$UscMvGygRZY{;bvTM=~O?)xn5(ZxEC$O_|QsuF}P$AQ2aq!|M z^@kQ^q!_MWXIDjk=Xc*@vF0BJ78i<7`yMqLd6(>!Nq=)7OMdK6imQ1N zWW9+ZBBs-+UIMB#mi?WaIgq>Sv(2d>zU}#38VUTNq9sSRO;Bd5o_YiGi6qot6n{ET zj(g<%B{!CZk5Ief75Amcr6d^7e8EY!Y~~C3Y1flM3xwxk@C{bAG1GpQADHFM{00g8 z_g$HS5<6c`fF6=Dt1HTNo18O=1)uOn0G!10duGQ#rUI{r7~)H<-Wz@+akRixBx1B= z_UXxsANz=TTo9KFR*O&$&>j5Gn^&!n-SB2I`53LS#mVHX&|4Z$>A>bu6YNTbogd0 zl-X3qf$Zxsm0tC+B^q((`Y3-N$j;cCbDzsMW}y+ctde&)My=Y{C#yR^*U1)tbD{5tIOAp&e`8D71aa}< z7=PJjwGR^l3C)tjULTmNBbuKU#hDWL=HeYtG#al-W91 zBK3!2L^Do31HG|5JhhaUlgvi0lRAFvKlQ1QDH?ykF$A)Bo2S9;mu#KlN-qKUkvN_M z9rE-RQaBk=n!K{-M=vs?FTF#H+#}jcja%`V2pfFhBbm9q0BiJZaF~}}HMJFZgGryP zwFg7M>b=wje2$5jw2PB^v)xquUd-J5Iv>WV=TaZ3XKDL9)5yu8==)URSiNfr5EHjG zr6u!Qjns^&*wN!L46?T$`~{Y=XCS(d*{CR2u@q@q_L5%D%%`^7Ni*n`SL_!Z9K6V< z+lYj^6mHmj9(+7%p>8SshaAscIX+hHszT)iKCU%$&hU{@Pn&H(j9&|H>J`G=%6l4I z=!mLCxND6!m;^?#I#niOTF(2e`PbG`0EF!iJO!q(n7(gr;%=ixFe}I>zX(d%a@u7I$WtXzt%Ld~g4z{3^*oh&m-Q+?CBF7g7q46tOo)ftJvuAe zEx;3e+Coah>wifPgPyQbWoon}sg+5pvbxQLKTbC*nX=H%^bMOQw;|`uQRwoVsw&j$ z?Zs(#zzZgkrTayYCt3PXo^iT1VWy{o?*wA_R`LC{M9zVg=`7Thq2}EO@Ej9XP!Ab% zzmxcmYz9*g+r2QOksuAMrb>ed=^wPFzlWp*-na^1)9WL<7Qkr__~#R^nvPcj$6m1l zh2CG5|HX%kw|}(J`pDOAMX&X1I*;=`LefR%7#-(f%W;w-ujwhUsd_C1~TMC$!GNuKTuj?b@w= zZ~GuZipaOPPav61c0tkq81VhnX{}wZoN{ljGyJlDP;UPQDOLo%_Lua24r{n<6!6)u z4aCU<&k`v-hKDun|I~8$Kge?tT9R^Kg`Jn%&B=ru7XYWToY~Xx_-GsA5ye$>AB+=n zT*=G1{gh?ukOA-KjDHA zvSO0AI$RZRQAm>r#JWK#3HUcbXzsymP_hJkyEHfv8T$I ziA9em5c@!zJZsI+uP?7Ejq{j@!n@BIzA&aZGL8x$dwm#m2f9UQvHNsTS_48IFONg| zfNj>BnLpPE|C>|!KRn_;J%ByKsSSn$L(_THOs}T-Ufr!}SE7%oEl?|TeogahHRSxa?WtjZib$WbbSd^*!c(;LmyyIKziSA(%r`WI# z>{bjA7I(yOdZEo3fmg^=T0ahGS!RJs+kuYhr%eY@RiVWwXDHLwUfkt=V^YZEj?S_N zqgWf?jE%+Ng#fx2ELhqgb2t?R$vWdCwW@VI|1hn(!K_nHMG?c|2uoM7V5)yuDy zt%L#J-*GXTIqTW0Eyp(M;mi**SdMgK9xGFb5-l1F?E5J% zj6Ud_Y)+jRgaQ2kJVqbrEq69%`y#9DX2mHsJLKauOcSKyctSMVxX ztJ-0nr9CHRdWGL=VbrjCVsXbU>dxaQmcxbgpq0gmNODpgL-%w8@mAN5Z?s)ed4pgS zdg}B%^!-z*JW$z9x!O_ZY2>BjI;cyQ^n*yT7<$q#?eZI&xOTTm|M$-*EmiUT=MxJ`|7#6Ui;A@*KqJjCEjVdYbD+*8`mfk^a*WtrZ4Ur6%l%Nji2@9PEuyz z7_oRErx+mW-EcV`){d<{;Y#4MWvXlLj|e$eK!5}2F25dWcJlIxX4jMDV)u@J;%YsMUx5g19CWF~MZ}LafA^qvEvP^?lwB8L)M=-X?C#4&|!$(Al=t(!|{4X>e(q70LA>|(&X}R_X8$Az zXgutF@!r=6vDmS}&RK>YRoMcN7fuBFAV!FSyWvNY=z+YInZN>Uq;Py7chm3QWDL&# zpo67V#!sx3nfmcoQT0qXxxv~k+fo*Y*zEGCT(21B38aZPGS?V6M83*@txay$<9PnA z%?gu9$sv1*to27R%uozqVsu#KB$HJsH?+xVds}@-beYR^G4GpV`NKAWk|!ZhbP&j;2i)zF9KKMbcqW7JQ&M3)JaMJw5_Gxi>(g=D z={ou1CqiOM;5}Qm*!z@InhWFHT+qwiEq?xm&EqfW_kpiKw3&z~bp%A#@ifVZT=kN* z`dd-<%sJ1~1aHqxO|0Hw{x*CAOV8upU87NwI6|r_hQ5)fzp84{za`ZXD`=-%&{469 z%ykA00;l$4m76E=q>`0#D}v^?%GM5IgD+9%eWgh5 z?+`f4aQ+G<2eq)XBUx=pqCoNGi@JxqlR}OFK)0nZd$tsW+--j=ECER7E|PKO94Vtf z1K7a}sm9#6On!BIsefeaOX6A4#g9Ef)VzxM8hN+M%!hI^vS6zM^!wpFd{3R)K}Ls# zjlRBNfmu-B`sPpjYC*2^>mOb5yiJ4@!*|2mcm}F^j-;tm?azb@E2f3~Ny&~Z9Wh2h z80Ea!LPfXYBt%v`YwAAYORwAs1JzNPTtJYP(X4oh!X!&dkk%)I-96*bPNzP&-)#(P znjMBJqPqU{RuPYvVbGyx(DH0v7ZPDRmU@Ihu z5sH|ktVIDGd$=gPw|sQEbY5^Acs?8*x6y93ZHSn(*@5YJI2O?cnM~1P5U*-1%cR(C z^vY|39vS_6k=&kHauE1>rFcqXH$dz;468m-wyeLqamOvsEWQ_qnOTf)rGHxmtAEc01Qt@NSriivFVdgjxCb~@RZuOJb`?e z$Vm+e_t%r4GztC@h|2Y@r+#X|rLs`Uw|ZGHxqY65i;ibXfN_!2fX@);@!`6ez%MZ= z)nqHncKb^Z4eO|Z-e-NrCz6@PP|c;rFaaC z*q)W#GGX_uc;|{vINE>~-oyzpn^R*%wWDX| z@Znj9N{%U{_VDx^ke<}$I}7cjM~i6QE&)6hgVJAb&?1&#$dC&~b8u_sXDXjK=7X!B z0skSAr)V26YQljXt_uCn{IF zIXt37sW~BoK$O}=#O<=nF&YotT$C2A*c1S#>iNI|>lTon`$xf%pAkjY@ELN-wLSC15w$||$NL@mt3bd4s!!^RbXD3%Cnr^QlMF1$ z&JkkdfE!Nq>M+r3C68s%Vl_41`MEB2+KBSWp&<*ru!qr2nEOvM16Uye%}cv-i41~=lqDXuBsUIm2TII4$Oe=1U|4fYLx_KV{5s(9Dj4hS2Ou=Aa!q4`i|3+xYg*uDD+pKyh z`5&>+uh#QsslhnTX~#zMiES{)fxlSU@_cAzc>P9G*Ap33O?eFe#4;Wvg@C!~z|vKa z8=P5!hXCbP+FI&ajiEaAeR7?NzbUk3T)X*tb$wjk*B=OYa7@WsUuWIDaWjz)U~V8X z3|LKf;=YAM>mma@gbFbY@iXqL)bL|`yGMBhdyP~3GW9yLx0IX?kCDMuQ~F1FG}_sT=%|w)nFgmHqCCzn5?g6Z&-xrrC!FZ3ieUNn z&Bx9=PFUpBuJ(c+4e0qa1KgeiYgCGBUwa6oyl4lhz%iXAHi!#mLSaUND)9NF?s|qq z;nZMMxvrY>^55JocTcmuyEe~Ms=d;HuVkY zk$Rq$!M;{4Xo)RYJ|8)})Q@EC3-Q9w(nGqD&G+92QLk3^g4=|&q2^JUSs#kE-Wy9$TlWz-EhKNAmqyJr%Duh8Nu!4P z<>tk>PATjhCpvy?0Rc(wPeC_)>sgQaQuW{VyPwP5A(KEip@ZoX|8zY&~d>+?KCz z)V+}n@aHZ-%}$Q7j*oqnME8MFWThVqKQCiQmYK0d+#Af^pF{x-jk=m1e2-2{6Z!2} zfe;Jxd{sVpquF&~12=&%0_ULuE#@^1dsqJB1^)pO7<9b8Wk zkX)re+U>S2&MKvd!q?nC;;Y24>uKGF?9v2Y=wTMQcrIeoBd`p3cb~K4O89$N1Km~V zDSF$kCKn6PMs3|HcV%!Xfyoai5X}PjzzUzOd$n^fkLbI2c#PNU&;vz!-0{4w-tDHg zHBE2%uNx8zp@-BT#F#7v0W&^r9D$hTUjI}d4nf)&bx(lqUI-UHco*M2C&Y46JONvn zv_sr4-!1TQmT~&lQ>_sVGS1>I^a)NRxqDcpw&*iJDOXcb*4weM^rxoQC{@(OcGzR4!>O^#Gf zvJX_-NjQ<#9;|HfIJ^{mKcr6gu^TwtOdgtWjr=j%01rKv7QZjt2z;|3F){khww1}T zkJ|>yTQ2Y-#l*o5>v>Gu)3bZ(CfOY!l0VD!@b#sNZ8Z;1XFm1IyS$MUPbq*oV%x5v zXol~~!Dpo?LO3L$eWpNlR+$W zYNHo1f`=n71dFcS*%~ zgNk3FM_2A;WOwka`zmLQ9F$i{yc{nUkcN;QgYkBzsG%M11h=69uM(e5 zbt37D`#{nU@h*%9id!>JY}ONR_?xi&kNAlAGvVLxmX9Wh^7tOe*8EX-L59)PZlXpD z*Us+9HKuTA9eD||e4Qmzs%Q9nS-X2XYx@ZemRRt5<|tX|wyLR{6AH!#zl9)x5F!hB zjHQ$X7d}>DfyA$L5Mf+*&_VHAL+aFPFXSQLZt_|H{mx@S*p3SCGyoHjpr?9E*jfH9 zS-t3U4JD^@3Ql6#k?M5Nrs_QyunG*ki!*!pCsgwvK;FOjTA0RZ9rj7sttUa^IuD_7 z?=7L{A6|&7Rds8YYDwJgYEBXdUa%wL&-GkKi&^#SMQI~ap}Z;ZY~y?|L6Qt2hRzhV z!8)md#>az~MF#GhaNw&Ft^R47(l)Bb-uFrPOPbLleP)2A#T=pv5P72)WB7Ps((UJ0 z1PLh|`Z!1|CTQQe8KfN1%K!=1c=}>1k4vE|UpoL9V*%KBaa^`A2uKkquRkZVqCVLg zF3@TR_OQ$pFb?db(-H~X^E$;<3e+AhtAaO{xN0bvNjO(Ps5J+avlOGFkcKoDbwp`E z>BY7Hs`xHBS}$t>b`-MWoHVckf)J9it&P79kv!N=h%ReCNE{AV?{S_F7Hn^ayiSBF zv(!qKdD?CAl3YcS8`1n-9QU+p3UK*R=d#M$Dt_=uec>h1R@Xbsp^`5iIeaS=(_OZB z(l(?2Lg_Kq=hg`xL)H^rNyRhw{=h$Hp@5XlR62uy?a>2DWRxl^^60S|8~yaa<$)}^ zSlbh)*C&@ms4%FHD3jf-6ojuB0ymAspnQ1>5#J|v2rQZH7FLEIb!kjgTe0$6X;fCo ze0iHgI^o%T!b!!X78Ug*$nx`7obkk8_?p%l)2Jy?z+f?0 zTl~%fxpNXdHqjXdh*uC`K#_fZ1P{iY+_%1QINt~Ar^9(Jd#fjr_3s=?pUIeXE~KKl z`WUb7PuexF8a*`*2}uR%4=X;AXJOIUUQ9!(Q27mZgHDHP1MdXMOkoh-?VgXU3B_!B z>o-Yz4=)WiH}gNr*9y^KmoJl{@qOxM>yV>DH;_#D+v4)yJxIU*o)qKLSn`8)9%6`~ zZSU0nK&iTG7mCk9t!t>mm|5!OUW`k0szU8qw! zFqK2t`ucKAU%scM#dh}fb`PYdx6drC4*|pUG%f!Li4S%7{e;H(?3c;4j)+L(wh$2k zC9FFv3zC}RKDiC%pkcFLb;lW9E?|MAC=*-c)4ea9u62@A%XS~kO-O}M1!&C5pp%`a zCaMn&mU;~7z(9C=>k+LG(L40?kYj3H7qyFuXX+)Y-5xMsMJl}h$K;j&tX}bbclCW2 z5!NN%zdo_bxQ#1My(C=J?Z=0y;jWF7J6ja* zhR+}~bYQf*s$I*TJWOp=r})YEU2Yh#9_Knt^q$rchONA-CZ-U6QU_c8HUJE&6{9(f zEH?Vft1nUVeHzGSOTi1DDYne(&FDqcfI`TCO{3y9p62q8A8B6KfdHu*v5!`l!RI zpPxB%EQ%Ly(y8@TTO5`YSHE9CDmBbj(mOdwz_2l0&rLDo4Y8f7F}f0e=P|=$BlET* zU_8oWTL_ERXv0SNsekD0<1~76J>Zg(zt`Wnw7^-bBLDpkskCzKS%rMQrPs2{2F02z z?W8h4e7$3um`vnT2<0~P9`5G(Yz>w8ss*94vIyiLg%o_y%zdN^KpBc96RkoGnUP|B zGh_yyst4vM?>q`Pm~p_jN#CytvavnVsgS?+7?H|jlD~tToEkvvgl!)@HA z@_xs)IEYqIwlj*=#$xxzgULoKf947ilTJR1O&g`I(){b~qzuD*LQab?sOF+e6s|Q5m%(tjb$EI4m<}K zo(%rnEkV*04R-H*&aaq(&4%M9iDPhj;qG-3EA?7xM02u%WGdAf1;xUzPlBvOy;f>I z1yQJ%xYvy|b0_oGC8k>9Ya)KkRTWV&!&Zh&X*Ge7RSJiG)zrY!-bQy56-gatt0h zNOH42Zph8z(e`tT@%&)pNP}aOe$V~oj5eu; zEmF3w12ol>1GmY!n+uNOrrS%LYIVwRgsBo1MB?l0S{zDx=F9vFvBx$_iTSxtp&b#Q znH3^F0fxFTw9>LtiFWwvvgE=u&NUqnf^GY#4dx?06ES=268G5l=y|fJ=co#<%1RZT z%fkyzOH2EC^^I@kX(81M&=h)f8(9ul&`5A)as2@(JjDAA-ePToD~mt0!2U^DJihOf znkq-9Ry2`cJP2n8&8mgYX!YVJO$_raM{5Gzc_Hu^$px@5Kq=c+5F(s9n=3*f8!RC1 zXZWGGkMmmxI6IJlze=-yUqb);p{gP~Jv;L~b@rR-H@F{5fdbe}K)Yl&&v|W*GLBbd ztmaYmacmiUTfpgcM?}+YfLIEwhG+ed@#8kZ#k<(;(aqNM2Tn#d(r`4&UunPiv^NoC+} z+=&<$48shFcAStO!F`UX12oikZt%gHuC%!~dBRP03y}we5weHi&dJx*A6_Yj)Qc(6 zZGCI?kGQ8!7J6c8HI#eXkKl^iM4m%ZF#g)!)c4EezVdca%m0m%{a<9zKiB-J-kJJ_ zuXeHU`!l({`gL7}=|9-RU8OyHB+%ba>A$^=P@2&;x z$aeUPe<5%2f4KbiZRUxg%?=N%RdG(FVbpKV|%V7aXjp>wQLIb_%>fpPFYTzAbg$f)WP#o_j(Y*9`Y zuA_Hdrp{SRRyB4Nn{;`HTSLne)5Y{SDpQPUi9Xa4V8d()Fz3yOa0rNl@cv#>ybi>8hRemxkO&GV&xQ`9_BgI zB<&)?ec0gb2tz7fkj~4NcbUCIWo^GXg82ZHn?)&>v-;9ThiCiOZ|*u@OUt*hE>obz zeVaniJH72Nqe%|7Iu!H$vwm}id_rn3f7mUtM=oT z8nr8Gidja2)ksKIGs$m=i`x8x<(Ya>iT$_obOYL@_6Jmkf7;iTQvI#+Du55~+%?)+ z#d)tS#JZ7ZX&ri*eK1=LI=)dk8qvNItrRrveG-%l3Ws-Q)y34Aj#*pY&DrE8AHYzN z&b+~#MO1Qq1jFZ5ce*XO;UVCbE-vJ$J1%aKDnu~7$y7Nsjr0A0xMx_IfB+zbOwn#` zRan?ng>ar%OaZjB2;`F{PbiVQK@<*lk`RDzEktlY)nbQuG}gQL!I5mHwr9{%>5lA7b!a;Ayj5+m8elibP{sW?3B9 zC-}Eh@P+wqKK7M|Nlkm~MCJ{eCXDVHRdMjZ2Oy@&KW7=ez~G6w??gyVSeEuq4rB!` zw1N&}VxHXfGa_Qudk+-p2FN)NPDdR5rzdwz^#d38&ZG&=3IVq1StTDfI}2X&{Yx-A z)d-fWzhd|cUZu=)x-Fn;RBL!Hv#mC?0=P6MG7-#PJ=PgNBkvsao%9=?rCyuKYLF2{g+2TNd#BG^O+9 zGyxB!2^fZt*tPSR0oVC1ca~}s#5o49{&eoY1=_rLv3_oC>p`>rQkv~oxmv;wz)|Y<;CDE>1Ck%& z9(OvzYt#X^B#g>-Rwc$7fT_A;=h(g0ZejeN8wZ0o{{<4Z(QLQjoij3#4O0UBRK3u{ z@oPfoey-Y`|5sLRZMxo299vigPkr|JEwi5B34MRM4F4qF;{cFV^=GtYD%bXPE4{fk zZ!+ElD{@Kh?-n5ZnYI+;X%-AefmtSXYx1X8*UAWd>*Q*zDxWkZh#S>=gkaBU-#hr5 z4bU;g(>+IWTRFT5dp;hs90?)pn)CJQc7KOkIgQaxhnDM($bs1q!k=we567rb47*rv@wYq5n9O%i37+`LEYm@z=JdzO!?Ib^N^i zH*vYA?5Df0V&kjkv7lWVJanSchPBdCi+|OZO*9ltUDjGR*^F3RVuoSU{5*AQ8=yJA z(?8VD58&;RqIXf+y~>FA?`<;4s~3Ky=oz}f2W3tO+wI<98h)KEM3?c%Sxq+@-}aV= zvYom8^W94MdeyHhEQUXxt`b-(3T@$Uo98r3?i4L(6WQ=GueCbAYg0aSRuc{$-)8b8O1F|KE;fpF-h;<#sqZvkf_PH{ z%2TJn!*RGRKq|&x|5ok(enJ0xe*RzIm7@CvCWQvYI{|;z&~A}xSB&W!GR_1jrfTk% z{myPp&N{iUWqO}K=*}pwBKYK!R&#z7_JC>#2l;5IZM!k)gj4{T3k5oD`{A4{$UT$&A_ z`L9L%kNzZZS{uprPQ7B{+ev`82^1UBZ+?Fj2eTtO$Iuv^PW$ULwXooRpW)&K=>s-d zpTBh@|8Yj|;^_&q@8@v@6Kl3=hN#}nL5acDqZRyc2 zx~s^7o7lg}ys~CK-Bg{LmK{xA=es@lz-7M$E`8iD#S8b1FnRLpd5*Y$K4VFcWM;{; zo&Rhy;Xg8x_t7u(4VJ6BM4PO}Rbx1?!wqs^zD|@PX;(a2lJtT!fntoquP6D@{6arP z&$E#SFTCk(KkXR_qN%z=Nv>BjF;;>bZ`dRbHYA!;=q;n}To?JGbX~BwD}sqB#$b2# z;>~}Io&NU^w=aU@bQ#iGWjg}GjeF_`<^qMcYyz|Y#WH*d#Y@w@u(go2>Nwx)B@wa$ z&((e=8#|<65Pg;NR>$uNF8{%{lYD;dv?AA~Rs-b|s4tqh)mcJ$^UoYIU8T6IOYp1V z_F)4TRX5QePdD8W(>pCcQFks4;)kGCQMvvpnAM>o`c{THyYPY2AwkeZn@0lP58rwB)=S3c#J|`RdXz4oWHK zyo%d6k4%(*Z5%uRf`h|R5`x<};h85<{ALRi>*oh*bQ0tpWm;S*SSq6F`}CVw*)GNN zY_fY3KM)SgeY${bwp&hXU${6gPid1S{~ylc#Ki%Ri#u!MyzfXXM^PR5zGuW9pCh*Y zg~oq2%(f;Ka$l=~vk+Wf^{4RrP zhtU6Uk^C<=pyyR^pwGrU)c%Db+(}4jJm^|rU(ETk;cF=Xv$@`vEGn9D>oS;E@6+tvh1UO&oIxR&-xBIH4gKNM|+zL*h)v=|6tSpf!D(M^c(}WF~a!W zm&(AZUx$3i3vm4a6#00zL8d=LE|xPYlrDuv-%}Q1fJy_L&4~9%;0atywBz7VKW4SuWQ%6CyE)fvs zL@=lTx>t;y@-|B3Cy*Jp)Y?V|_t5KVa^jNdsUI1Z7`&;sr`O$vJviQGFD)?Ux zjAR($IkuXcxen_et$%H~`KB9ePZWC%Ys@vWU?dIZMyVGdX`@P~Elds6mM$g-W?XwnYK|R;7?y|2$sXq-fL9$~ZI@@eHL4;@ zQmi^IJ(y{$5PbRbzf`&XUvsHX_0Ujgs*i`iUsY}EVYl68b>1uA=C!m>eQ5>dezgS? z-xR}&KD5wHUMTI_ej1qEtJzxVGc21_1o=yNdRL@M#>kOR@BWBFAcgT&-UT4@P&Etq zp|qq^zQC-hjf^SL?HbcywyaE3W3LbcNulb5{*A-mqcIq`7+;tYY#=7P`YTl0JXbRkvfw>VZg$FKY9rch30=c6wuWiFOoqA8^}cF7#G*tJ*p4Wjxw<38BdOH1^<^T$i6uLI#x0d58Vb-! z#$zqk3(t~Dt$Mt>l2pC;3sh{TZD%9L!il4RrmwSATxAg`gZ9OT3JH}xiaKOJJu`|B>HjH+Me85+5UX1f>3{OjKX=O z42%6L3apJ42f1f@QlY^}r$f>Sz1|nFpiUX0F_?FZ!$K$&{OZ}!1MAq~Y(l->%~%-* zF>Y760LPa^pM{GgKYzzQ9?l*rc0QM=1kHe}=Gs`v99dE?o-`FI%)ff;P$Y9$s)w>C zHt;t%d0{UJhu`jZI!q%Q-r!HfmP(k;bLMcj6;vXDJiYEY1;I=~Yz75=O7I6Pk51|h6P%-wH$H#aU)4P(D zkuAUmOW5?|FN(jL@`7$fpbcV+qU3-Ep<`RI? z`UND{?a@iEF{^tdb=c2VXv0{{@k@F%U>0U__7JySElg$Ayto_>H>qVZdf&-)jTSi@ za;~x(LyUl=`^(|l^hj~iUkW1Kkj)TzARAb2m}43Tj-%$cC8qgJR?T0ifHn}4Ua66^ zEnQ`0E~dgSSM!7hQmw(Srt!7Ua%YC~Kuvu?wGY!5O#80mACSl0Bbplf?Ys;EXkji7 z^c8$%cevX?AAxRkNZtv1Lmw(slAYN)zVP7SSk-oCW@JVvc;46+a-+5VFt!r8Yx2ac zeb-a{>*Y3Y=u3yii0;iuk za)GlFTB6st)+mPdSvC%Hme%Q%!mWL>!c;6!StHuACzK$LP%Ku~MWd)QKGz_QVQ&wK z8gQTn6lztgO+2>K3hG13J2NIkqsZ_8+%Jp@9CoIEsStOM>^9RIe4_MgJI z`_Exz&1l~(JdAGMnBV$cQJhCCP~6+MSO@Sx0RT7ciQ&Ed-bsw^a$mAj_SMxbyQkL9 zS6smk^|r^Gl@s{5LyLXfw(HHA;^!G)nvoi&>&QEm^j+*dMr8YqQA!|)3++y%R{-)w zk{dYzmq`l0AE8P)g>R%>VJytJ&7_+XrCu^ZX|LtGM|Fb#H*%A|$( zJ!^~E3i1NoD$r&h(!TV5VgYsxTPk=zHWdNLU}>l`Vlls>Mup+y_0hwpOR#RMaa94h5JXf5+A~$eZpUKy#Z=~b4M&gE$_zdSssc~J<#I>DdsesP-r0ph+ zPXH*!ynVqfA4VjWGusTNLw5qv#^DCjwnl^`x!8EIPPZ1x4Q$+o-n^LlWl|^j(oLAp zT~e)q6%_-8y^6y4`e}0eJtuCbC;UNiCDPCH%L`2O-sU=%6{O6T1nYa0Df@ zj-;9Z*(BlAC(`7Bn10xJ>(hY;F|tXb+hx zcbe80qM(&y(K}>mcR}1-5Rdq}PT|6P?#-8yF7$j$UEi%OmtML!tM^rYQ!KVpzFZ^w z=CU<9z7k;#ubHhZS8Q^pp8f=9*yR(cMsln=4x`04)Kiwi%03*JHpi70zE+31>RU2r zbv+f!rkzscCOLAvBXq|GmUSyv(db(L4Z{8}py!+fZt)}ZX|)pWi92W2Yjwlg$#>wC z%0<9b0WBBp<8Bd$Z=E0geI-o+^4>;&I<~xH2`of3$4Oo-2%CM|e06W3b=9ro27p4W zE|W`~j^qdcCm>I$S_0UR>BC2AY!|K`@SA}z*#&1Dchtn904qmjJ&}wo-uC^qNtX%Q zwh>@_#IV~Yg5GVq{efwkb?y!!P>pQc_+#ekbTI+Xj#Y7v{jy$vf`6jI)UeJ!|5&b2 zO68{4*k0FeIEAH@>3?2_97U+Af7YCl}@nV2^|{L+2RRRJf~V|hul>ewW%V&G zm*g;f$i~>E?lzTjUS8e$hX^vXbi=4)-D;^9j1KW&a1n1IgaCPsMWIYtCuWc+KxQq8 ztYN%H!0@u-fn44@dD-s+KbzqBUvWCT6^+VIu}!$4$aTgvv%I~YDswEXi6kt_Lc_SM zWt~xJ?2;~) zN3Gv_lbalfCArie|5#lC)Jb_yqp9!N11-6IOI^j3YAyIGEf0#>y4Lys5L^lfj4p@PB~+d0E*qq=pAra?3ELv(Edms5?a+j|C)5 zL&ZC_4_x1^3Frbo2OF0;b%ilfL;l|y`PJZX+E+WM#BmBNX%1UF1+ zrG!|$VbCd~iPnZPM;_4w)`5;tSySr4GRyH*tqNtm+>h1VNZso+JNw$I#&2=O%uwgz)K3_R>o{vtOucJc34Jo4 zE9e{{3>Df-H~e>Cm1qvj7l75{3!rPIuclHi71o%i0Fya&RkTTOi?RfH=M#n3?=e6h zEnVz0YGKz;TE4O!Au=(?uVgb1UtCU8zZ-j&Wgf?PEuSIoSo}4paK#+(SOg?2mRv3* z3aPcSzs|&R%ZmsLt6qKsbSjr~HF7W*J%>7T^c<||S&aGqNDVr36bFOKaM;sF2rs6a|y8Cz-`S91J8&0ulZbDe~h!%4KbA zfVZ(}NVuN9b8AQ8WD;A=KX)K-YbR#9BI6XtwP;^VFSa;PcZM%2!(C*cL|)qv#2u`S z*7|7D1&VhkBMQ?t-Qg8ks&y6uSPGI1P+%!EV-)1bpc0FDIn!@{p&@zy>O4k!`OuH* zT&@|+X}D>;)CyEUzAX}$s}Hx0dxQP&Qy`QN+V6iq*jSeA2GA(42ml>eqiNt z?`3EJ4tvwq83&^`ny+lzSV#;U6p4c?sLHl>Q%cyZ(#N@UK=2G=GE4y+K$e%=22# zO7nPlzU}b?JGpW|9uw0>5SaK)LL;cz5%K^7KBlVzBTWEZCqjwqYnJhPrLLus8u^H&f(I`xuUi6^AX>ak5N(0MgO%zh6O3o!kVhoCz%>pf_Gnr3lvD!3F)Ps6`-MI;Y-)4P~ zPqzn>gi0;X530NiHmW0vU*CyHaeud3o089Qkyip}T)EB!lJLXtnM%2-+RJV8D-iN5 zDdmczkK-gA95^zovFBm%M`#bwFYvY6t|)|pu`3=Y7nsil*B;?!>GdA}xs;b| zHtYC66jM|>QmCMSz*tr1GgYqkXp8gLUSyq4S7fNURuaYc51UpM77J-2&u*$M4(Mp= zSnMY51Jf4(u;-_VMUCbqaXLyM2)TS54Fs@DE8QwPOi=EQu*tlU6T)U~FkU`_i7CG| z16sm8rsw72VPtY-i~)6OwU}f$=p=+Iy$Q^*hkamGNPAw)P&bpLTl;lS0uj&)FrIG# zRTw8QrQne9sEgNO~_ z!}PGSJjY~$2%ZO0Z@}@hrM&wqNfvC@r}_t>+f5;@Kpgfi?Y1r%;D|N4QnoR+)KwVU zmE^i@u_j+&M5;fUS421@KY;LKdFN|t1!$HiLow>!QNbvhbI~5!ZcXVHeEGO}u~GOe zY$0_@aOA@3F~39%ow%~oJ6!*yJ8EDqb>z`@zaFPNeG%Fe$-L$RLWx=snDQ2pLMs9K<^ zgmFGZBK8vP#vQ>y0~*c(Ho&1-d+t$ie1eX*9pPjzU!p)!1+~MHqTf1hioQC>!YD{&W@~1 zF-u@2PX|~Q(p^Qy^6=W>aFf#G;gh0Gg^1FL6zXlD*a)g-xGr+=syW|g*R8H_YX`?5 z8p}Kw*MOP%bd_4$1>YPf?#Il<15@XtjUq8$N-~9$_p}@ATJZCh83Kew| zk8ck7tS#HzEluwVZv{oTn+I%InlLn&E;EV_rbHxOk+vq02zV7);8pUJW}`^MTSbSn zqah&09EbJP9&QrQ&X8Cea&etaYvUP?KY<8Q< zJba}hiznmt*Iz-58tmGP30HNA>$0Vs?D$30b+iXeBd1aEez9!F2fDAWlC{BmW9?E} zfE3(T-_t_-yA0C-(d4R)tNuC%8ZBx39ikRzooM>Q-|9*~&ir^GJyE`sa``+~0MZ#_ z03+Teo)69H*vnCw>&4;o1Os;k~|a>8YTC%@bsLyEKFdQnisHaf|ZmWf6I zrZM@97k2=bHW^-{r?XsE1?=1~7qhrg%0ryhfKUK$a$K6d zg9okxMv>0S&&D99H|ZcC1$BPWrx)ad=??in_m)M!qXisv&GF3_)=P-yGGS}a);)L?ERA6Og;Yiwp@mbO z;)hn7nT_4c_lLIiW*IuU(>S_)MBw>KyVrcE64J~Us40yFm;4`UbOOk7Ba{5js|^C9 zzJC(Mx6P9>I-UK#o7pV~G^P(i!4{gxnlt$5Hcs(3`JmsMb;vLp+4FKSka>`!r+=cl zw<}E|0TQV-vK|47L8YbHoum1aY1-MvR9mhZY?&4Iu}PR>fonC{Em~njl1oz*VCB`| z47uxtI-{E~`YTM}k0qfRAydGfBsD(0$M&XKJgBymeCDfKsb3h7P(6t988p+A99Lh& zcEvGA<*A&U&NFJdLpyxzV-Z^tT}pSX2m)dG@HKKauMNQV;g#2p`+S}UKer~zzf6?n zD7DI?wS7v-VSkk=ALMj8my9(MnP!W~pU7${|Jmsm>p|ucbgLh~6yMbXwjqAJB`Pq}fb+7aNYfvaCOd z-lfiA$c1u2G-b;IG$8gM^H2U)z-y1K&>lO#a*W=U;3k6^qQWeavv6Q_R4BEs2 z$zTkTW|LQ>i-URIEv1THLmx@c55rAoQ7E@Ua{NxI4y zRU}iYbP7Mlc)4@6)Cf1Q?(HUjRts%rKHJC#oU#V8g=Byv%yd%qvc#pfYA{n$vLu*H zwbDX>t|nms=mkMl=Sx(IkS!1(givk8O{6fSFLu^ni+VraskBlmHA`IVJ_{AAW_|*K znnUdDjXtUR*tFHY+H5{WyEDF}Qpx4oIHu;>MYlGACk+AV2`ug$vDv|NK2h9iP@(Im9uuZAYd?#s zH^-|bai~B?CS7>meeiHYPM{Ra5#oRSU$^HpP{D!?15pRHS(?H++IM)Vj(HpMiraDibhe5!ieU`U%vH5#8|cSmDB-VXx({rEUao7wcKR+WSa~2Ibam_G!98;Y)4iXoOuS?`RTV|0)-6AyM_$u+*_w2w?um2NN*p5TPO5*0 z$zY{+WZAdPO#~XzhbGYYPbj&b-hjeeCp0_jiHlh{usTg=y@g@f>WL@*8I}~#4EB|X zg+R#rTHPNHzl#kDydTlAb`nom=Q&y*iScYysL& zHx1sJ!$Gk~EzpZi4YZdkP_NCY%n0G1FooVPovwG)7)F8-gk@AYc8YwLmAN2$4tg9! zhNCCV>mRlqPj{1TB&pg*`g12Pg)<79^taRg;w1x%;DLs}`N#r@d^wX^w=db%SqHqU z;$qpNB5x>K}=4$|9$>s{>$Pp$m zx6LIKNm4=&$-F!Oy(|<-l_PpW6IH*=+7s0pep+L+{!>9_bCCR4%2-;>fV~o=KwVhM zzrRFduG zD4_ctFLEyV@fodaGjm3hN~IvBOY|$*X_fv0TM3SvaJV~=mYgc#DkiCb`uv$cGDS11 z58kBQTk3Trl^<}(z5y(TroD?dWl!@%KSejm+~H9^|CxB}#a*`vBrg5hHBlUpgZztR z`v3mQh+vn&tsR~7akfd~t)GY5^SVjCE`aXDXre|AY^cRvCWYnq?pPS<1uG%Nz-WT0 zV>!3F6oJpa%30c-U$O@?OHta=a&xHu4l<#@|f`YCymR9V$8o23c<;oNcMsG8u2BGXgep%w8eE4r1RH$Y2kR zYaCA!Hz&#f6p;p(+{2Kr}So&GCKy?YoSFd+!4uY^o>Lh#J#8VG?xhp`MhIlL& zjBEr2S+OpV&<0GayMomzJi0ycx@)dL7UoPOB9_Y6V%{PM63ae1?y|7O)+dH#BeZFU@^YY0tG6x(IPXN_;31N_n<;m8o&*(jo6ytR43iqoo}Yo>&2>=*7!n`R%Lg~ zPW^t#+yBA}iVQcJ+?K0w`LdI|(DxwcGsr0zL*Qw0a8s${;MelO@}Wx66!T4hZw}>% z1FH`7B0(X#uq!IM2dqwwf`akCA=J-S=o8I4k2MW)=AkiAVq=p5d>A=ilF{|jG|l`Y z+Fq$chE}GQ5RxbuT~Vuy2b6@1?NS{H#Ptiv>Jit>wvky8gxJhbp+T5mKTt?8x;Ixk@PdK>+o#1xrh0p^}}i~ zD|wRk3~ss^J#iJGtJFeKBjiaOR@@8Uu!8>c$bJh0P6>hK0(D(k$`y<0O%khC{Rdhi z4SOiOA6e&46OAy?ROh)7^vbFvShjX6MY;f=3aka7s;W+4RFuw~aCCeua)L>J3fTkJN%J+anHU?2$XWD{Ab{o_KON;B2M;*RzFc-TJdsQwXw9P%CI zd{tAp3{wZ}qef9-M}PTuMtBoB%@BY>c7(|2AjJ!B1iSQiA6CfBH8-ZVq+z~UNPBlK zna;4>no$vLdt)lQRyH3J0|wMgv--KS&bV}=SIS!d!2OyXdw;o|`wbfyjEO+RL2v3R6FO)`>7 z#Y7*6!R!+W!HV(kl7b47*Z~N*H^V>xIrt{x5h3UGQ9|RNUE%Ly!SI^SgojUvh5}y@ z9HNv(qitZU(;mV?E!2L-0{8c){vHPSTB^NYEkg>Xj$378{FiXx&!&hmOVzCb8`=3s zhv7h*%+!!(N+d;A+ir`3&Zwj6R)3Vt^mlVUBoy`Uc2X$t#qMfn+kZD8Xy10iQnSxWJ#Mg zuF-!Kl0PMHA9!M?`bWT@_we5cH~y<{ar!e|2+7Jy;1-~|q08R>-ny?Eid6ql=T32V z5WW;A5gT`(!>s}C_RTdo6TiUt%Ll!CcwDGIW_Euu{$|(u&F^+sy?x+^XXwFee^t5t zSEfr{b$7t(hdU3({>WhG5pExNcZZVmzdF7D;NOhygj+~2XUQ`DsI8cu-r`lJGbq|8 z|ImappWSJkhDa???<}oG_|A(6Kq4*vEJOLrERYcO_V)@A*0iXi{4wEwCqE5lx3J+~ zNB5up^(pzCgw1zk#pv#bkOOWXnC?ZrarZwo3BVz{B|gFN{T8#|Sn)3I?Um!4dKdf0 z8U3Zfx%1r#uN%$BqKWR#fkX1vrJZrqGsge3tHCoDbLZ9ey1zdD^KwGf@0<^$@HP71 zr5=Ag6~D=y2%CSqx@Y8$b@GWD`WBIMZ`U=y0251+{qXNT%ip~~lkC(asDEhtd}QPy(3C2f z#7Ydb@{x~C(*r#f^mfFmFdf9pw|-LkAmR*dH&WVDihLkd$_oLb2peXe>Dh4IItk$< zQ^rSsccy<{KI~7CJ6p4j|^!trXg zJ5S5g-iA)O5^JY@f&)0JR&cg6f!&r!xipK;MBCNx<%wKQeORz_%&?H=(3H9 z_CoTj{*C-t*R?U%XUifaigyOM#3X&A3;PdT=KuaJuuOM`4Ly0ORX2}t0XfInAM(`S z-?gMbKLWNaN_oosPaU{@d0pEDco zS31R0XDYdlHWe)pr^!{ng3zp=f2~7rEVW)8R5-@rNRec<*;J&{xj^nZ48FD&1r%>m zsWKYJyQ%M2|y*OE$T5E5D{zs(P0ReX2eOO+aA@F|dwRykbv@k5ExYonu(+BPmob;#`6nFI{oxF1sh@k#1d7bA83(zXSbWef6#A&Y+E) za-%0?U;`3Z)FLTV^jYZ$7v)60(70vI%^htpQ=D_PUnG`Z9p`>Ud@2#gsL&Y2G(ZG+I%@sUOgC5&q`kCJYJBB8RjT82cxj%tEp;?h zES)Zm;V+(RGYu#{;gI#%lFXp;O?om-n4JKwtJBgU)x;wQn;lkMHHV8Vq;QUL!@**E z0+DdG^rfX|1^yJZ{KHg7Y2Q%w~-F)9qyOW zEoK$Tbl>OdOcXGX&BrBGm((qv22!bIYGo?R6>8c^uI^Z+i82#|QICA&@du%;m!~UW zeoi!Qore4jeXDE|_{6efW?)Q;eHM(62B2Qafmz+WzBaM`Fl(e_^eYr$F_zEQg_yE5 z)I^=6cS!}|&XJ))HP87EXMQ&;Fa~B(dwu?R<-hX?a|(B+eu@^=m>AcvM1I{FC0-u| z#y725zI)Ryx+LZh-{QUqW&9_p=f})S zPo3o+t~OWOONa8PQqzpRWtt=ivhSfE`CNj>O_fHwp&m2-pIu2F+&@ScHjPnBD8Avl zAHDWoF&YG}M5lvdYtpm+*TSN{rOr%~4un=m%oX3-(8WN)uA?}@;&j#AS)fUIguElU zxlMZ^61&*=oT?Jk#jFg*RHZY7O^y}3#9TEZi6*cl;yDNm7@GNZ~3Krd|89S0N7`1-G||T?>O2{9+G7Heno~VOL*KJ@6cw z+pzYekFQgi&J54&6^{Q|B#_^_qR(!(nw6(mtKJ*WNe#BP_EQelg({1pl9TwMaM_r1 zjjDms)=7@qZ3VRuXV=43Zjr=I#!If85q{_C8(*SDEHQ@UNIo4WU2KOJg=g}SJSr%G zM%>hODS~BRVA_DnS+;rAT;^~DSL=tJQk}s&m7Ub4hV|;aa(tKr(bkihQI9$T*I2?E zcSAX8bK~}pF3%2J(p+=uWk0f*r+7L{v)U<0A56H;ecPO{^FOcTYkw_FM7 zj+vot+s*jO+u3JH)d$%bJi`hh66hCwgWsO;(aW54j#(~sG&_z00KQeDa-AGhIYbsy6>u{zDloBiIiHDAfq`I<70 zIgCUq<@@x`)G5cxKE*XvLSb{3t8!{+n=5yYWTGlgr)>}B+H~y`O8LU`vRBG-jgy)W zs$XVWR8j}cYM8b$Jxbl}zDpotOgSI?o$LA+nBkDT^I;r)j*XR<1YhM5jRqi(oWEJ= z4++n{+Dfv2Pw)wyQdw5)R3yL7PD2H|Kw+#r?6B+y#6G^+Xgyk%RHi+`^*W-ze`8s7 zc-^U|{;DZ2*Bvw0yyQ4V{*0c<+R6J+e`z^iWg^E{FHkpIwl1wMCu!iTd=9%cBrm@H zv;yOyGpD_@Fb~wV6BGx)ln#w85U&c zUAVfeJ=wpHHh#wegKzo3aMlq+rdYo0_ewP(-z|>{qd3*6yx`CYnvpNGK_itZ&QiBQq|X73Mok-lL}pz#3&WQ$0EfA!S~)%Tqyoeu*moEd7%IKUm8%M%8S3w%C~C5)01gULQB9T zc#zUF6u43K2C1@qT=Vt1Ct12Mm4|1lpg?GM*=qcP&Z3y)p$DXz*YAT@Of=1F$!e=J z%(wAO8c)LmF$Qqpm-|w`oV-tIy?hkBZ;6`nWO#=`pv<#l0Ogmv4rBcrHQ4XNAfii^T{Ff2iXdQbg8Kx7Y<@i`&nJ;tsxO zT#Z6ktFH*brGs!9GJN>|dWrwGf)LoBo$f9w7(SlfDFa^`dZ!;X7>;9dIas~tCl(a* zpzyV_$a|Ep%ph-E95rcXx6cs068K^e{qu9GuL|3k&x)R0)_n>jzU|vST~Xaoj;|r%9;8hag-eF-R|+1~#Nri!lTG@{H+D5u zhJpYo-1h{e*Df`T0F?!{$4tF+KQ8;NeVu?Nvvli1j3tZQ2Gtk>F?N3vXS**`=1B8? z6 z)NG=&k7n{1nK~La_Q1Fl<;BHW_-w91;q0!_j@J;L(jXy6&<6=TU;g_uo#~c%E;V)r zJq_KJ{`0GQxQWcCJBja#`Jawh82D{_v^LeABiWCxFCE~yIEmws4D&a>_NKyCX$(ux zwRidz{U(Ii7V(u(%jDMf=)Dc|u%%N;$K{~CfIARGCR z4~nC58lcSP09JoH=^g{LWI@KQ9+kynas^Xps~11MF7J~>3A{nC+J$*k?-^II-7ue; zi8|Kmw$1s~s^f!&IjmSTQ8h_QLy^MCvGUPU_>dlT)5MXAeVAiX!MnOVk9cGGsi_T` z(eKIU^F<$FHo5J-C}4Aar$!}D+36>pi0DFmIsEc7I^~ZN?Kgy@Z8nd+IM0I{nuy5l zZ4ffO`H-eko4kc6DpM zPpmoHcyAl`6!;|~NoIV6HGXx)ro2Z;IDGZ@Qw7Y!gC&BFzRLNxzK*ImWDBs?UUdP< zeH;Q*QNftIeh7!Xv`5e8l=Hos$o%;;&Z<&5=)7Xw!RRhR`I-(-e~;)-Pak}KUu~=3 zypU1D;j;hOp*na@fLxB`fwQBHC!p!`cG+;+$0GB<6L&mb8)~YFS+G<0G1*2&LFrT@ z8c>r)9DUAjW3=-4XhSx<`rR)QE&)wa?{;K;Th+!#@+@Etgin7;OAHs!4Uewg)WPa( zG=_TtZKU(2K0koqf-pNHANllni@nrf_F2CYE!b2%w^H&6Tg!{J2H0v-sS?8cr4Q13 zQ@u9q9eyI%9!f6pe9bztp@xfYfTfX>B0q1$Ab@ zH%bwMtMgeKnO^tpGL}8+^NZOCY7X~yy+-PWvYmIEP@pb(Z%dhZVegyz=GGQ2+_|3U zw^r*H8$zWx#1dGF)fR5jR-FMbW@M{a+)1oDgew`^>-?jqrf$|RD-L8UX4Jm&R)%p< zA>emKklw#Mw;9Sl+c?yoQ;KFA3MXdB(|9%!*DhW92{B?-*6;o_PQ}(w1jl2X`!!S` z`1n30cxVeJ5GDM0+qtS~GQ{?ql@|_oR7)v`TWtugv!_AN4Z?vDSP}Srf zt_?O^C@n;o1Wv2SOcO`6l6;_byG6avXB`aw4Rrnr`?_%_{4xFH|Cj0G<0335mwkK; zoI?}VOk;DKX5tE+dI5hCFOAiE)AS&``-#$@1bVL=;aVjVo5QhQj(RiY$99fuwsN~( zHF?I@+Ob+aK8)skBln4fea1@&`7Dt2ZTZKA&ht0PMDUODG4iajTU&v%X;1k!!^y@I zA*%C)iQasjgT?t6sxOH}7kRNG!J|#*jW$RW&YWq6+cB?u-pW>b=-J*n3wl{u#>>u; zmo!e@42eE{UB?OM-?h@V4}AJyEb`wKpw_q?Jfza7Y=kMvjdG;f(>BU45A<99hRYT* zQ)ihprm<2joLj&Gm-|G@g!|cw!-YmXdqY0^7g9M@?HH?ofFeam9m5*0BAyI%CaQrd9=+jnK4L$OZ4hhoTzWXtO^LqGQm%uEK9!LJ*dAvU24;= z#!;l_m#rSfA}AC1>)ga`RpJx0PsZ#U6f9*8vyU5nNo$giBK{yHWS2Xn^wcFxb|@0I zotGYKETDs6t}rj=3F6ZhUC#3-3m+IL81y&awjfz&*o+rWX=HT_qBa<*&dPu{2ckF<7{kWU%5cP_2e* z7Lr^_f7i`o+sZ<9F=V{47p~Vo=?pC?$lS_EzHE6S{x$?A)Q-xZXiwEsGKq`tgo_WC z;gD03_dfZtzQk#;K3@FfF*IuSYb~eQnkVxkdov64xJ>|Z%>VSm-NphMX{4(FG_nwM zK_pvrfiGH$9|X_N-n=1X3tjjAHi5j9PvraK7~kM`-cjal%^-kWxx;ghLUFS>&R~8R zS($~g-|#t1IZ0^?kGn7@2UEmtNFU62MS$6zBs_O8hO@i5B?No63&Z7f^$HIbr6u@@ z2uh1bsmL?li|?9~X+rI|SyF!=jV@ZDjnqN}7w9kN2^uqwVB#`{GQ<9)vQ3f=^3M+^ zJ6W0}!we=c-B@3V&6_pAaZ#W;A8n0ebVgbCzkCgU`dT9H5guMLhopk1ryl?URe^Bx zm>H>Y8aQJ?4({~hekg5AD+?W6U(IrLsuOEE0KRD`^=r0{TS0Uea~>sIGjMNDs7CxW zw$E4-fM?tNz$d8j!mG<319cDZ#-TU2P{_AFEY7DA&vAWxj6OSm27VaVu{`euBj(Ko zW}~&@e)s-oW!pUg#h+hIo~-tlSIWzP#(sx-xi08YUT>Du4a&B}79R5)b1uu)q=PK`Q}g`&#er7FX)`n5Hq(5Lv5R=xfZ zP3J>IU3vd0UAN-EWg<%(GYT ztlXZ(*E$if5lWzUeyrUYt*-Bb|CA5+Hmmu;fiz6^l*X?i?nGm5pbH5ZvX(2dL`kU~ zg-fOVHU>6~C`eCVMmFgmR2F#fdEEKn1Ybz~xw;xJf}wSu-5@#&e6xktC$RAF?qF;$ z`4$*<=FJ+>@`wY_A46~=-hRF)zl)X&6}1Ddb6&|Csgn%@$QKvs7Dua13K>@B!U=RR z98X*jnN4Qo;!%p;feDrGu`K0=(XKF1=18AhbGv_NsP_qYV1@f5gigoe<4hVCIx(l~ z9{jt0Pj}&`n4`J(w$R^_D;BoeIig(WNVbxfhQiWkol<`3L@}rLJ6HGA5!Fxz@~IShjdnrjhsAXsev{h@ zmCNPg$AOfp7e2X+2V+6AqDJfXBY5odCog)`(2D{=jzc^DUO@N@4W8?BK*w_cYE{wWhV}t$Gx3H*I6s?n|=DYbEqNNeq zj`IK#96k)(B!}SG4ke*)Y0rwE;L#&w9=-OB;8{9_c2i_-2?}8o92}Gu|0lE`etcUW zS=dI#sdMrf+u>?nG3CaUx?l-m=aaVhTuP>65b(F=bUFlgm!Lfpbr;`2VER{rw)~6- zFRie!aNsjZkd>L)CwR0&?5qI!wC;}rcdjF4q$jn}TjZWV=(CJouPy}>PbH?CqK3ss zZsFJ;>V=L;(s9vz9CE@cnGhnT(!qKBD2)-S9LK24J z&c*nKFcOEu34iK+ZoAAw0S96u$h8>)eirq`yS--LJXzr;Fhj^ks!8 zyV4k(1Xap*(!UtX);}*b+)9i0hyCp61v?bY!$?890ML^vjsIomo9EWvBi>nh;62i{ zedzetd(3k^o)UP`H)HF~+h?-X;OK=jcZmm}u4sAatKZ4PAX8$JFiuMjLGavk=FXfl zxnbIgIJN=o6au0baUr)Et#*d2Up|%R@KS)r;j22kK7r7+aANm7{X<)+{(QcbKOXvT zvb~I_xQ)sB@!wGY&m1q{87v~AH&AZy0ik;-d1YOoMbRSad2Zq`Nzn7U?eO?(SAX0YMrmk?!u6 z4(U$m?)Vq0hxb5DWdr0V2ik-sCJKN-^>&QUCuqmgFZ ze=n@G`6j(e6FnoV$-(5caA-9HxqEpwzfOk^Eb{)IDV zK3+h}%~?2@%$|crZ}yEGdoFC?sakZF5uyMFWPThE$?m{2l@zXSVI`uEy7aj4Vq&<| zbjq{d8bh_1%aY{f5Ne4*Fmfrds@ z1;yvdH(l8V#@^neyi3*-)FJ)Pf2kB1S__;#dL`R3_@52Gexk6VA|{YU@fj>E@*J65 z4h@pX?{NlM#)9RQm@U_O{)|$tsbY5H&*&zWjGlUL1J~?*i$1JZdcI92=n$(n%l?h> z3|nd9>}2e>yzkij*QEhlZBIYMMq z4m*0X*hb{-_z1e56NxThog??$aP$a?^PJ}C(<(n9)<#c z8HQIh?^P;m`(VNQ4_v=*iLq&p#N^P!ebYVf&=yx3nS|%Buao&)USj;kaWK3*MoG$V zS5f-oKSADzV426J*YfoYf{*Td6nc{cPac-nz^%y&qU4-&8(GH16R|E$6IfVb7BH8G zLi&$06{dPX`khetPMOlj2>t9(GPWRQc+Yb6uZn8+Av5CL<{E)UY^KQ#567tOzBKd=P zWXMD5P%vqa6na;Q58&hDBLPbYYpI}@Z;^JU)Le7kkV&lPAd6&Ir4myWEc8+tHPZY+ zqnPC*9RQdR_~Jr|39WV37zbWS&%;URwbg$0bY}fv}NNyVKA9(~oMu3ym7A`WDm|xm$*vjjoe<5oBV`TQ*fD0l&nT=chkn2`Xt6Q=?CB0^eG3Ee z1LQbF+6^8ZR#V1zd=ZsOlKW!ywek&y zEkTuiXbnT1u6PyQC04xspLa8?-&4dJcmwrQpdu(9XS|^jZVETx9k=??KXs#X>V`kP zxa2Tc!hZ(=IDXX8oL4$Z>+QwCPz#i_;^@%W;*#iFLYbcls|ecxBLRctdlWP+-}Op;VlgaZE%eYa{z^1JkccyKMy&(zr|s0XGYkny|LhvNdYh2udQ3LPTZi zXbyFG<7GIFSi_C0Uz#nrinWT+u@X{rIHmDhi~XM^2C@D^z5nCIY_%0`B@B@6)VEf8 zj?DUnyRH>zv3WMiO=Q~Ml)xi|3wfO3^E&OcZKX~ie;btWzBvW8Byopw>=yeqJg4nxSluR{qU>-aWLwo@br`^Z z2L54mW|?`ptM3}Kw`l?sTQki0bg-DEZyFrl^2rIiHYw- zSX|CcDkiq%D6)R%&UUubd;X#8*wLi7bX41zvA;;SDlU?!t8Ui5XJ}z$$xpaN-~Y}p zU99gT!O|H!zqi&6kJ&HNSVEN7e*wr0C`^b<9vafeyS`KVKXjjpAH+ z_PPOBXYyF7WsQqs(`)yQ6w0TP;NMI6r`E8Rr(qK9_qhKgnD(JoCm;!@#06oIK8q$V z|IsUPw0h1bSS?tzD?B;28Cldz!P;(Xo$abm*IwEtCe^k%IM-GejPst<#LM-*H|Xr_ z7u%8M4s72?>R=lkKH(H@d)b3DxLE415oZC_C-YJ_!OEfkr5@>@!W9DO2uf8h#9`({ zh1sOQ9HwP!SkKSsld5)NsJ#FFTmwKQxG&GQfc5V~29Mr{?=ZU!q(e^@sCGjzmRfv6 z<*a;q)oWeu5wwi6XMVZ(_sHgJ=6qB=HtLZV&0`dBCqzC$4L;d;EmrSjj%M;bx8&qJ z@E9joWVX_LdBi`pz{F;$4n-{V!zlKUz6gM|jhha@GaceKE&$#NVjUsQ6z|?A`Z4Ng z)tKKn+M7dDg`iFBYT>=ix++sRB%LQYxv3&5Z5@}vdUY^Ur7=wFa1~~M*Q`Gmh*;ki z{>gu&N{j437td*j8Bl0`x(uaE8q)E!zkHpS`@!Ij+qt<`1b--!BJbX_h5%%@qXYNn zrNsBg75rYu-Dupmx?JH^CLudpxr@B*$7gKkd*ERyZv?UFDU(g*)GE~^c2G9&U!!om#ezyXc8gPGFTFIX{hF|Z4 zyzUUHdeQ?TG1w{jh^fOVskYt$Q0+|Z6uXJt+AXh`e@arEqcRoH4adJdqcx>#XV$_M z*L0wHg=zk*DXhqnZrHn1_eGWbe?d1#WBoV)T<@NMH9J&}NG)`Z0A)_Nre}wP$S^K) zeFXSwt+vfQhON88EbA6}w$*DM?{vX>0DOSNVZpfyBVc3=!F8ha#UMtQt2qpiO=5+r zXYY<8(fSUD%&4?%DqESa()Rw7WYo|+MFkKs$NZ6pqac|7I)bhbqTSdJ7tWnqTFmi$ zoh0t1a`2S(e664?vCwNQO2CfPm-*eE@sU5Gk^-^_+ z@W*xWMX3E+o?Z1^O>rP#qi0aA8?(@-I1rRYjr{xQDL)Gv7NL)B_qikbNTXmQ{8^fR zI8|za0vmpL8x(#JGgYj!h5pGcDpPH^cu$XulNqo)D@ zsqyRB<&m2JF)iN*Szq4#=fF)Rz6^#2iR;$dK?BLBP}{5cs){(b-*Wo)Gi09EOQ_~6 z`aga;&0;O)vk}|Mjk4b!$!yHG;miFQ&G>gPpsJteBBa5(8b_LMcEo5*xE1L}{RPz( zgWDf}H;y@S4)k35Vt-$`*%2|2iWr5G@k9)l8m9Z@sH0tS;fxNk)E?i5{i9U!w3$Ev zP3L93Q@X!8R>owq(awL9L#e0jw6gl5w%f-onuv+fc=!Pv=L9LHH~gr@<9fgkSD|xi z|9Kf87AwehOOAD>ms%cMT^*uvWh!9#eztW;jqm{G3TSFvs?8|Cddx4t-Ii^sr{1c?A%OAu=|f5?$0vng6x@-yZ)7A0 z#oA5iwJ~%e0dO(#4Ec0Avm(x5le+Yy?yjaTIc1B4+?4g!9mY(L@%s-MPey~$w@sCBwBBQYz2cS-fi9FQcO1n(!Y#Fu;$$Lfhd%Z zVY$iuVHF+#NBtX6dQHj(pL#?Emrg;)a!&@t#$upkpJW?Kpojs6&+Aszuv$pOLiQ2S zL|~S8Ln&DO3AFG)PQ%p8P?}Yru*)yC@0>zgd9ND#+fuf4i>2(JTDkwF&r*^QMiMF3 z;W7G&X-tu3({+R-vd%fea3tNzA_(>$iXcTvzz1D<-{0W&$9?bK>UlT(1!mhRpGXmv z)qV^$?frpz{i@)?$tv+y;0~A7kOGYYA?ydDNw7x0{QYL-i0ksC_z5Ysn z0vs=hS|;z-Y)J_n;4Jy7FX7bVat9sg%OUQRc+ZwI=n#Gen*`(t$=`a7b~2ny-uSm+3%8U+A>EyaGy zr<{!`6iT&M+FjRsfOGPWj;7mfcL@D8apii2^dTk0|Iev!m;2LRkJ~al<1AvDW=|FT z!yf^E?>0w!48s@M{e1%nF)$R{aq`nU?;dC1xHja{nP^YA^#a|*- zQ9?F%ru*U}SB`pi85cY{DooonO#qCy9nXMa3@0!=HNal&TBqUiL?=?B>jxMXH*+Zx z%#^7W-E6nf&kM%HE2`>tr^#8xA%y>I#Mx3q3Ox<@+FQyPki%++y=7zrZ=J=WMM9qk8-v zM!nIvPL+UPq`DT9PNg8u!##mI%rkO-n^9bxVmT;$+#vq2P+E&X54nK=2&XGj!b2mIpdMnJbk1c)=l zOYrMCLZpx=31`b3xy~N7Do!sGqOx08d-*Xpcvm@#0a%V(tUQWMPIFefPd1lK%Mv9jW!m#rempB3c>fI}xo{;`- zvs`4#WDZ*tFq2M52-;5j1nt^7b^KNDC{F8=FI76uY_oOhN1wgvSKAXgG(un)$rq=O zSo6Z)Eu262y;U2TX&7EAbzKs{7qWrl=CDSsrO@c=uW}zmc}!bA{WQeDcXYhMPd%*5G#5q!TxOmDc1&NBNnUK_zUSkIjm&rHU`q(gH=;wiu{I&bYD=8`7rQGA=fec^ zN8IIGvNe+RT?t2mG+mJt*`%x{U#Fl@zExW!duhmMx#pDH7F8k|=Z3c|@)9oi^1Gf~!eR2DUdTt(Hx zuJKEK+F-7i0e_I?I(aFbO%9)$kFG3TP6H>Zj>6HmH}Y| zlIMkk+WfVmxN6xO9=E%zXJFl|ZB*E5rbrA1EODQkvuE0~PO9Azkr-n+azF5Xki6}F zc{tMIJSTtPL11^ry%jX27hh*(n6FoY4x&>{?CFV09_R{o3xMf$82GS!QN(9=@)mPg zYGpnv*pVDTlSh-K_fplBVimh&gV|`4KZnbS|EgUZ6DBE=iWPS_AO}76aIq=yg2dA< z*KPPtm1)YsptH-Qwigw469tQcmus1uIU@`!{T1qugrWf2@ps3y#Z*w#i*=3|J3npv zPwm?X8MVdKfSs!^Bm+?-3qQb)M=*O&J=o?BvrbBT*C|aE9$(fnR&X?6#{{R%O&id- z4Lkl)?Ii}pnBRLd1p>2suO{gZY$DLI6ya-#SBl@7);?%z`Dq+SWc?gTAr^%(e72x zb$a#Sd#_$*nB@El*bjl5Z++Gg*JlL1r8Ob?{U^zFw|=nz@2Stj{Uwa!xyLh!NDvI@ zN5-6iTRRZXWUyVz(ztW&Nb{D9TG?{ytw^@rTX7cP1)6MMY(mU%)f<#_J>j1W`Jkmg zeN^VfxC2aU7Ao#vrk|rM3~6hcr*N{s!e>J=+WbznxD`Sj83D)8z`BaO_I8OyX3rrQ zL7E!(HA2oBg6Pj27p&$ds0Vu?r)~`{Htec#C%@0BCY%+pX+)a%EkK$=THK!pd2q5F zP+cbN+M=aZxsMYHOUW3uO*EIG$p|7cT+_31`t<)ZzyIaL?w|iBaXyZe|Lj&)ZhYSW zcoi@~AUJe%bj7bBn~z@gCX~0@`C%ghmyTM1O~NwA=}Vr&jp4rsl{K=PzjK zDfIcBUTQIf^;J9f(QxUT=Mn75#?!b1xZ)lqLQr$)<}SkwDiB1}Upq*j@N5H=!8XT3 zLDH;+X|FK9$xGvz8$4SGmT_n<=9b43zi`@zDHf=Q6vt%MkOIQ5E3DzEE5=|T_L;Jc zOvtCbdY{kWC`PH#4DcntlJCh{oOe$HhT6#V)x@2t??p(|8>wq$epPU>hEndJ?+m)^ z7!hE)_FJjg*)bD3T8?X84bilfPdM9Z*o-B=cQ z0e|O!uTlySxkAlfT@n$L(6{Y^w`T`!X|^8%siK~xd!zOulDs*-VO})VXf5mjR5F$*KGN04wi@f>tz<8E zdUeAIiZ@p8CvqG;OJ!2<-wmaeNP)Ow+vPd{)4{yYrVtTs^i_42{rT(x-|YmjA^L)o zy>5LREd5zZQI$bbFPn>Yb&54JhcjM!ODkHgELtuSrTxKo{gtuCzMMsr46CF!1%v5) zuB4jvPV4S@u+hRmRdplYdbAUSB3eWKmaOUIG1VM;NhJg2A6{*TUG_${`2i;qA$VxeLt%=1?t#cd%L?SjhVPDBm9 zkAhb>H=+sj8m(Pj5?p+*hbD_(yhgwt8Q^)eeLQ?^ zD-haIV=GpRk4cwhhT7#?Z}6x8!*SjJ1je5PSjq-QPTNJe?kLh+ExDNm61GB$u(+NG zn|QRHsnH!A-}S>SPQ{9t{xXV;S|vE369j_J5Y`Am+6Gq7UF zYl(Qh*dHKWmdNk~0{JYwY)U;I-6-X7?C-?X6)~=EDTj$bQ{oRZ6ww|DVT^PT&XaQT z>XfjM!5cIkR*~f)8VP=yBlxY0mXHDSP^f4WEF;{_?q9z$?IS_B!CHRBS8tIViMWa} zKG9eZV;N)7L_vcm`%nbdA2uW$YyB|6*sB6_&CaRiehTkJifI}IdoRWIHCk_0ybmOn zoc`Tq{EtVB84nkPDV`QuYRtdl9EOU_3u`^=yrJ{s5fMWMla}+x$Da3;odNKtj(NRL zGcG-dv-spVfZhDf4+)jElMwZKqS!uMLEi@$U`SQ@XxCh%*amY1n5;F=On;v$an}W` zR1FsAe|fDza_sQ2%Aj$E;H{Uc8Q+h!ly?zh4<*x|YaY>wMf8aR$*6Z{o4(?sx0htX zMZ8gWAg&l}o6lJoE8CF%UD9C7q|Ca4!=;vv56Lx8avyzLTa4cEZyJ`h&bR1)+Ty7J z=U>&|U7{$nDLN!i3%`F>*d25)n9OAV{Z?aRrUwG}We8wRZ-9*fiKwhl80d<1adDwc zA`_eG4uE)}dS9lIN#vSQvBJk1`e;slP<#K1IM`0@+^MA*e$QW zAXVrUk9les^$0q2-GXqXG5gAXHT6;!oj=fJ3j2F`m>8FlALOUAnY!poB2l8Bq+sehJ5F1%c+6Ejv`WUkLc@G%I>_`G- ztvl0vYnibw4g;bS(N1c4#;4(LvzHr5Ta!a=Ula)ije&K%=((d57nJsueUyn6Uz>5Y($r7A_(U4(IjdyDbM5 zjXoXkgiVo%6_)!tw7qCkSnXN#mzsX-?PJ6Kw?K@05g_EUuGXKL{Ipx2JdxYO&VTxk9leT{>3zEVN z4~XcN(`*OwEbI8DvY&m8rwDoxX7#g?LA%i@>9bn$IIw650i2^hZ%uvILU|{fo?mGV zp%hOrs1sX#r_E)%5MZhhNWn43kFo_3zd8hTro>%49E2=i%XmnXqy&)>CEORqhPXgr zLkXh*X?Gipt_1GkEIc4F3Kdu~T-VUzDhURRbdR`^F_ir9@f23BG#XT$69p_IG{KtY z0OkOFm?P+SYVTv2ki;=XGb|8G{sx6E6?m^P5umRfkB--9WS8Awi&@InzO}M7QX^kX z1_X-Pr)d`$+xK>KesVuu4?rat6LS+poSgj(AJ{D(F1j6-{C4$Se2C~qf%D2tg+4xq z15%}v3+vnWdC9YXu}Xp_sDHMA{#|;+vHVNn{6kKZKpOdq6ebgM)z-?LF^QpBQg?Yo zs8xAdjO9blJx1H}6UV)jO2z>;iL5lrb7kiae|x*#%gAo2e+rqnz+VZq(&OIrI+7x$ zhG{!3()HDc=xDgupDl8m$dp8vUvhcFj%86b$W5sy`K!c%@}dMCBcbV^hwk4rbkLcV za7Cf*q5x_y^@qI?=|Q&^SK6p`>vKrtu_OgCYGeK^)+o;Y5esy6!Vdv2+{XasEz>aA z0n_P*zS4Xy7+@MM5_cHY5;f*CVZ5%6Mqi@G8WwirxgA4)YeYIu2EZPCATd)n{F*ef zPFT@6W4qii$3d~#$~<4ajDLFO1)hegK>wvGz4#r#M1vSLLoO@4W<(i>-tJbW&yi18 zdFs^?Qy$+0S&F1D3ba;*KA_*#TKf8n=D1DOwlce)7+Z8KGiCx{-_@GU1HN(WH~NrN z9#27f-9}UZi-7^!^L3Lh8M`CL{I?QoH+BAXhMU9b;2<#*U>eC(?%|9;0;j${Caiba zg_VMd@~5}ByVxfJ(QAL<+HLBD?T;Vtln`321rV}CUhC?F);Ie;VJB{t>vf;!GP(ch zvj6>nG5zxap}EL9%if$XlE?W06V0zKrP}T7{3aQ9w;*yuQiLs{i~Sh{AWK5!1{o+s zoAspuiFt2cJ_@aFG{NK!C;s5lLFRRy-p*C4rNFh34Q`tbQGB$W-Co%mP9G`zM3=&k z3zr)KBM~Umn9%V)>GaAAamX`~P!>zP|CF81JHbyZ+^}Hq>j(%w4?l`*A#VVF@XJ1Q zBpy@nM_IUafc>%1krk(S32fc{VFAz*I#AuC;1?hj?*>unyi_~Vnr^SVwQ^+QgH#!k z2~wss{=$ie$4MDbU%i#6pT4#*wf?rFBBPN!KYx0l#eVY3*B~O;ppC-FwRUFTMbv!V zBGzak50)xhv2%&~vSAS!p-6GEzlGXgD7ke3QDNmN{DajU`@)xIFr=|N%Y(TOCW+Pc7NpUO1g5r3I4kH`h61>Qh!B5=zr2L+>|SaJ zl^kJx$iS;qZeAoDl1KJSaGRt_dho<1t__KFjy4~N%wYsyS&ehyJ zsa)K(_j9BaxVYVpkb*YQzp1J*3{JT+yiaD1ALdFy=Z685uZncJpF&pO2vsaWfx48%7SpdMxxnnif)V2{K%(tR(IRIKzQVA^D#Tvk=VCUU9&(rB@ zB?kcYZ5CgIx8F5q^m&w7JH6~n(sTeK%_jFPi+cB4rL1X4Sydz(DjBD6RTCh1T~;i> z9%efudape?(Y(PMvfBLzVwfPy`7P5106e4&?!&=3#pVNYjW-QP9N6JiX$UO=a(uAl z>kEjBmMbtk88#e)-OUyqSJ$UPx)0s^p&m0;-xGqe;3s{3r|7IiM2{l5O05Qkj+T5M zX^Yl}Q*jA@{=920dQKQFe&I}26WB8(GE!&RUyFEd)AeAR|L{2bxkOaIuV7!Y7>eBU z=h;Z35^fXgp^#TV{O(2TT+F4W`?Q+p7O$j4oF*>iFSxEMvgyRNo@kVCoEKr)x>R|| zuN=MHrJk+!1o|wz=ZlmY3d;vmVm2YUxw#2TOFu!7eHmYk+5+IK=E;tcC$%wx@v%=Q z#r@ja+LrhC2XEURtSGjT$%|O1HBf11mDeavverib@XJ|i0@*BoejBI>arX0nc>w^w zf2_=3CC$1Z4d)UOuV@zAb6#=7QU!b>7c@Gw;PUCYyXmiUP=i?Fy7kwXA;ZVx4V}O+ z*S1==02Q5!0Myt|A0;%U(Dwr-zA690?IdG30Xr@KN+YevK*otQK$5}y^`{ww0Yb+E z_vd~d^VTz!8)ahV>eP9Vd||ilibSpvT<|zaL`9}Vqqitf`cC0WO8gi3PsS6$NHl;?Px94WSWlSHAzt* zLeXu8#fYYju;pBGs~k}Kpl$R|EpGrLZV(_o+c^(>_L)%!I&ah3jdaMHJ>Pb5)5hWh zDK7|WLFe|EeqJ24%R3hiWRk^=(=kfr8Mlk}y%<3EK$%(iRe+A~$kq45wo;At%6zyZ zC$}qA`=U2urfYi3^{;TF+bUuK2?7vL0_0m#G-~9=5!Tw1;zY69iuOp8Kb?zW(_!Si zLVIS+>j6=RJoO7_2=E^cvx!^FXrsDrOyw{6YW(K6#6dsE?~1sS^1{Vs{+?4IZ9ay} zmeD7TFM1QgbcDD}i^>`ep zCgM+ud``)FWzE~VK&xc@Gg}v4I-ZpPoYDOOhi|~<>uUYzFZ;Q)H9zl2Od(xuyWK_E zlpPWbl1H#SoX%!I-}8&`^Ana#r(-XGsGK>SDjoC1Xd#36$tLr{FKH79GR4Pc4i?DHe|@I{|O zzZ;DCLUt(NGZa1K{3F0oXWX@xN+kQnJ3&G-1Wp%7!VKj-|8j(Yey{}nYb*0B*~>QzeS|(geB_Bkkn?$00iY4w#te!|vLA%zE_{ zD=@7e8VQ~>oJEX!O@@&_Uz*_+0sFT=LLgm0ed{O0s!q==Xi%H?^$GlHw+Y{AnSF$Q z6#1KpHmZoLAP9yI*QodS7m?RhBBDfC2asA(`dqn zO3E71gEolKx7wbe9NIP{?``nzlGJ-;WaaDpwH@LdgdR`J$((+#rd})>sQal_2Wy((v^7}+&(W> zt!9nCoZPWzDJVud2H1DSG6!qHpfaNnvD0@^9vw5)_hk6YcH9b5J(BZYG7LzWsK^pE zwptj!60fkg-dp^%8R&6g*T-<31f9l)aN3I@DmIdxG)8Iq#z{Vne&&SxPiM!Ex|=D_aj3-AnhyJHkK2;ly7XL}#|X^ndFW)U zG4o<3+lJ#aiwkLxCtZ?b#L=6gRPpLiYH{%$ zWBZTJpH-DEV}(*-`7(*Dwj4Ou_lV~frE-g>CR}yN`LzcNh_EYr!O33lU+rPHDO@~u zj9ijY=zIYU6e*qhid3PfR~phazLWn7NTP!@RoHihCi;Kn4xY{;ZDS_ISQjt$<)p3F zx@|q+s5e}bGwJ4dDKX|w6cMRx>B<`4u5M^Sbh*J3g@rToyanB&_fG;IEjS>s4@E>o zWO;cRio*i`!73I$dKG!(1-68bLmJCy`Zw?J3#v6>c{!Vf<+*O;UL^s+6ke?N-%Wb) z^4#iwpZcXh;lB&#Yu6Q5FP*w#rk4TXZH9B#d%PMsw0s<9Da>C@4^UQoP9a=zLZ;OD zss&I3I_DTdQm(!7@+uV0C(jlAHi7}%>Nn4l>A3ikjEU2qOqupQN`gme>Xtn;n31}D zVM_w&8)zF4vX;?;Z5@P<4U=7TmiJ~(J@^i}>>d2+)QX`Qk2Gt3hDKs;)ZagnBJ;T% zY`!Wd$HobQHEyb}((gVCci=eE-iCMF^f+PHz`QNVAUAtnqVG&t_rtp_ z)Vsjd_z+$S7cv`9n@s~eyX%lRq8v{K&U*cM@-hmJ`%pTcn614ZCj1UE1|VVWxIA1^ zaqap%$A$O#u&5CeE7%VhO-~CvU2Odak}4k;uWxOGfC=TuYr)=tk}*pL$lmDian;O+x&j=jd=c}Ylx5pb0qt|}?C5)J)JM6dX2{ZJaS~FG#1j-@ojuxm% zY?dvLb{4*7n6^penQKX@aIvlI2Gr{8{_c25@|F4mroE%Wq^TS2K>XdkS{lq8v zXtZ_{LlIaV8B!M@eb;gcFwm$M6@chKScJ+ZWc^?f#jrc94-a87gxh}gh?jflX$OJ_ z;Wx^bC<&q@?7aSpo~jMa1U%Gq}Kc1bu zBszrHYG_tG^alVs!VXy`;fzdTb0zHjnuQ0dqs^bpt;2(x`X`J#R+$3fuDq*#brCOo-*Q6cE-f;(8zl@&W>r(s4S`2G_4s z=3Ea%n{MQ_YXc2mqZ&3&FBPW}N#NW8wVw{6r?l2Tkv<(P-M>3Qg7ter= zpgJ?<11Sa@i=_k~^oW*y?vNudyl)>;$Nsh<{4jvXEf8F?DBAihQhPr5AUwVwZ!@4n zd#1{Ft1IESW-ioU zyQ7H`oNYlo+H>8Ob12ROB)>CrWzn_zjTMa}I-jVnr-=nVx?V-8G^CvaRUYl7*pSsM zQPmSbASIu&g&wqG-|cn%63%A96ZP8+$3r|1$rg1qbQj7b5||KPM64t5ONkg8Y_@BBuCp%)w%z0FbHW%55!p@* z8wv-y%+)M%utc$U11G%GNL)umRl{;$g<1>?iKC&FO*77#@sN?2RYKJSBdXJtwWh(?X zzf72}qg>nQeMxFF@6j8Y#Ao_WSgBx}%jjmJKt8GW@nV7IPH@A(c`p&AKoj%u8r1hu zxF7WD>Xx(z%;!SS$bCPs`1O)Z(8$tz^~hAS=tGPv*%e1-1MMQ%sz==o=OpcZ0cle^ zmKNEP7Sn$zsTJ__*T26xj{%4kJ7;H=rnfq6RK;7fz|zC5)^XC5=j{bUiK#4VI6Sa0 z45ePJoF^Yc{Xz1mWY*w0wWbW_HBC6h@x|YZ_qkyC1nxhe8>ZZ|znnoXMhZu$oT0Sk z7<&_gBivt-?MokzQ;?Nn4xAG~U6@>=j}kBYB<)AISY+0sF#54}RBbrUk30u6b8{Vm zq0##LvuMjr6QNTC>?3Hrl~c8>hN1v|Ku;CfGeV0o2dwdv0LdgMs%1KdN?xG`iz((- zT;B`$qnH|84g-B`0zETd#Yooq+D8qO@W-n0FxhTv?k8*vF&A8D9diCTI?Gr zGe9sa0-f45?K$A@L!DKNF5!Z&cofFR+!IYkX16l2H$z(Ln*OdwSO<&vz%RN1!$?@_ z2LNxEhOdchGuNJ`3oI|{QNeX}y|bR>t_Zi`YtGOgPJ;#Xzt43sbdX0sU8XhqdxHJb(`{j*!q9I|LRV9F{csgqO z3}uaKdY%&5Tv0sm)SOB(s>4`NEg(Q@!7n+d%3>jwX3Yy3S;_uW<&%ljIxU+pQh0&~ zlV7>X1bASTpK|E?M4<-S=1^LJlYeA33Yei|7=!FClwtez;1-oV8*@rz2M-U=GJ+Lk zq*K55#al*&-#D3{Z0pEYhIV&KZIvLR9PW$NX*?!f1UA#*tq!Zj#%GV#)XqC^?Jnls z@tO6x({H;6lxff{o=v;M$AcaJrRk5)RL1^u#u8uY-&c#-oemi_X+q?Q=JVn|KAg|F zZce!Rp->#x7-Ow=MxkxU;0BGoI0=95qusL4YqKdb&@axOHk3ahC zLFV4~7h+f(r2O653<`Swz*?4{r|X9+J;vx`mEB7R=sb!o8BkJ@c1@_-?o<&0&RW-` zwdgr935ZF%xdYxl3yM{&?6Y#lDpu;tySu%<8>?z4wZ61(o;hpPWr#m3rG#XOv*;bS*CmZ- zz3X^ZH&hJkZ+EaN7e>a!SnE8s*ek_I(_^n}0vgWhcwTH2BZfu2Q}~r?M|^ZW%A2N+ zTahu+e&M77uNW4Dwu1n|akaj+^jSX$%+rR86n(=pJ@*1`t6OCzSK)?Iv~dVlmN>!^ ze|;oFRb$$7oBeRA%m!Y#?JE+b|9r_K=C|fkX=J8W-o5uDZBYv9gBE)GzNf4{swdP?zsCbNZcD-me_-~~$d_y6g9^GE z(;Q2ll9%2aa+nq>Xzj>gQ3?L~+S*cQWsOQkWi{0B;u!pZz`(Ytsn1g#r=^`SK>N0} zVgDhep@C1eEIflQjNPf2Z#q+q!_hPGArH8Izx+YAVUrXAX!2i9J$@{I^?V-|CWXkO zJ7bhwKLL2yMRFy~L75ITi<5hP4*yS|TP3- zK18a>%Kpzxuu{=!%kcJjULfc2<%vp`_hek6DJM@B26tGn67PsOZIpI)ss)^Smqw~T zJcw7TXH&oIKetnwh&~j$iaMxA8Trcwf+j1Yo`~?g;WYcpS2`lkqnrU1QmM)JccxN> zVa34^Vvxw7z)4$RsA7eSkx~#@m;71nc7gS6@jQ<(Xv7)^?6E@0zY@dk_>&({&hjut z9Ry9Qx&?UInut8Fc3w3mciO)CQKaN5+iU*lFXjONLCmW#!l+mL%fLcK3_13x9gQ!5 zCB;d2^3~Y-S4c*4d`)H2vJU)w|dji zs%^FMRJ?}M?nm;Lgws@k^$7Knaca$Ii0*7a_UqrSKNJJZCT`Cq&YRxhE-^(-kJuL zm_1;4I0Gg7U{h6;KKxW3;Fs1Nb=B=>Cyqxld`OBoL(#~7Y_T*r@Aq=aj`wHdJZS@j z@!=F(KeQmO4}MCHydxowICjIItSm3lZ9o?hF@@&BX{{YT>B`t8{-)9vgySe4zKzY3 z@@xjsjMA=A|o$EyvifIB!^w*07?Q!9oOK(}$+L9an1w&2dgFmi!?t zdbRK^?I(NapER3sp#X6O8Yz~rR_faOx|9p+m&N9kY&qPiVqvgz$KmxJf+}YEdcjY$ zh)0I=$XJZ=Q@u0i0XNLlE%?O5Xegj1$h!U>pEr7MS5kxwfTp*n3yMY5WGE`drW8S*f?g-Y%`6nw z7li~+I-p5yI3?y9r*rwmYR~9Rj{x2QZtn+PFl<&>wHl3-?$2oyWb#oJ?78k3ZY7xN zYiCh6!n-d*k%_7m<*+#Vo9&Q{j1kXs^s8%Ssxt|$?(A3Cr^k`(rac7_T9grjfl0Tt z_0fjHSo9%#11weQ6mrQ|KB7v@g14&#BBOcuIQ6eCevJi9;V`Z89`m~ts#^tagRBI) zX@sX<9}BkggBY^huwVuC1RomWFDaq~1aZy#YXR#uxqNy=i071hNrbPojsg9s zhv&4Z*S&&w`#5a5DQS%n|1!>>zph;BK|f!LQeWclC0lfbDc+NtVw&o|ZyFGv$+V}5 zq^UNLpQ8MH6)BM_jGZ$=W`Kv)*}+pfRn)hJt;z$qUBAMRM^+A{^7Om5_DG03n2pa8 zAlxm0SGzyZ(Il^9hT|R~o&jW(!8xI?#8t>Ih#e5xMOO)kCKb+M4yw26Mu-v^Pe%*X z%0zhpo`C-B;FK#x&=DPQw3!~M+U3&k3_Ff+!+^J#{H|iquHToJAf3s30396c(t&Jvey0oTyn#F|SKFDj8#fPYVC+oIP`lw`6MZiayz`Y6*sw}=qwF5;BoaBj z(OW*NtHOck0T>9)Vse7pG{Wh+)?<(tpU;L>LG+k10{=sBiC&9nCZ&lRmUe9z3jW5? z!2%ydL$ks&w=CF29TChepUi?d(j|<(y~u3mN3_gF6Iyx@3b6!8%h?R7e}cGWv*HpTVY6pfLNeu#Vs>j#F?j6kYvZ$#T$(-iKr8dL5_jSwit`8mh@TsWt>J~Te z>+H7e{8&u`MFol3hBA|03Xhs6q(>2RklxKWqY-W+kj&Po(q+ZJiz3ISYX2j5J8WyGpVc>N8IjXRifEM zn$CB2me_UM?%~k-p=N#_(K1|n)E{T-X8q{G8YzxZE1re~Wg3O{&7F_X^p7c-r-qX< z1S*1Z%bngZtDEgLA|&Qt%Cp%6j?6t<8e}rDrKT+@rDu$^L zAq@|`zB@%BDstW|XGvGEA|)BT0>tYzrV#1b?&kB4B1l*)nc95;ie>M+?~#WU;B-R7 zdLFwVj>?6F+=3@?Y`VZFtx^uQUss4N?A#EIWFXmh%`P-{Jrpz4a?94ZgR0!G50(L| zF)Zbp6z-)yZMb2*=0OD$B@$|49((90c-?jPVv;1Y58>nDn3R$rVNL^ikA$G!W*d-i z77{3sWi;Q;gWbvc+#(Jd`Ao=c7duGNP`APHwhRT|w%$mRU4;4Y)O4w6H;aofaf2_S_SX|qdHGCkDAPEpO5ZtA3 zcXxLQ7Mu`*yA!-{4IbRxgA?4{Ex5buw{t>H_wBxKci(%y=cyl?f}*PST5HOfV~%N^ z*SF-a_5z1=v)oMhHR-oXmLfp;+vz7{Tk_dF&6D0CRO;>;<9dagy17Jd9DE7!OdC-< z4yLUYWzI&QreNjp1spRTuUk(?BKIt-!VOY!A^GIqSQW)rwMfXI)Nb%fjILwu~e}+~w(s85sO3wQO*) zD#ZfZ;S@%*-W^^fB(;Zy_BvbHs%?w^BQBG_%Iu*f1E94?^U!X#y;MULO|^Q&sTtcd zb>w&N$D-HI5C|>*o zsWpC}K&84c)0U-_7xfb}I(#$~||f1?TN?|2KVx@sgy6l@7^jvsJ2;XnH}8(wdsMitji8 zB8upcqx95q`wNr%EBc29l>U$~QzQlX4J?n~yCd#t8wc9j#!}erQg}UDS<`yI(0^9m z-~#$=V3^HVH)MiipT8Gv;Up)3}|_z6>d=n`tB8@xF*d5y}p>rAGNQnjI;n-SC z$rT`^^cx5;+NKn$l(9vF5=3d2qM-=(^0lgnQK`Qumh`q}Z2o~mH-b}YENW-WPayYw zY52v(hrB7jB+o=dsnerXz4CGdsY(@<+Zs32?18hhO+uy_d89eOoD_bxqlS%eTM(!W z5MV{^&xf{!6H=9XxrLuVW^5#u(w|Zvw%By3_IlaQ$XjrR0=XlXTw($ZAnwAv&Zh`X zZ?i(~aKh1;9I>eo`tf51%!)5uPTWsY?lU?NWn41txPLVrBZS^+{5JLYBnu9b!z0L( zCL*qQ!8dsOOW%7N^SJLZ4^q0clpPYRGK{=A;vHY*KJ_6=2&z;GVju~+fZ_52SKF6%xNRP1lw{Tdo6`{ z?mZ8riP%Cn4Y7QDa62FjGzU-*{$kC#!jZy>S(p<16IpaYLf2nWSn2FD@mB!z>Z|Y{ z($*T)yLoKE`lJs!Fd^?<;|3US9SDj#GnUr?<@`I=%rARbaBGT7FN@;H|CkuayHYeE!cDi4MgTd*%l; zachzDzQ*q6_L>ijqAWc?hsXX50jd#}v*5*BCck3s=5=F8#+=Y}196nw9?|D8wa5^v zjTT<`qcJk^&o)1x3L@ktM_hUMgcJS2Z_r&ibE#@+tCew|atJ<80Nw1072=(sHZEH&8&m0ZUB`7i9Te24cPi;;{MM6)5Ir26d^G)<_N&*zu@TKIabnpK zwK!q3%yD83Ub^Jef!qyKPp*520=mEMCb#{vKC7s`T_xHyW@Lxcp2<{!{xh($I%@Yy zi$)AsQvPdxX8U`Qv`osHODwEim4n#+FY0q}pjt+_(}Ts!^q98}Jw~8E3<$o$jiG-; zr7gZ7F-un|uFhmstlw}E|Oz$XTDV#rV6{{bz?Bs3%+N9S?YMw6pBmNGUGZhe4oY6u%3 zF{`tIJA-IeZ)kzM1Nybjkhkl7(?J-t zGIz}tzAZ3>%?|X$hiMgD!-t?#%W9jDYfnBkf@P-%@SJK>J?SRWaMuJ-9xfkTc3&VDy|5TOM1Sj(CdDGC2LXD~ zlnO9M;Me<8gzvBk+&|g0-XjRU`<%rV;90O(!-ur}_1Ut-LLr-F>g>Sfc=nz=7xaMH zEuf#T0YTU*vRrW0G0|ft+wr!!NukrAOmL4H=?=ca4AHGU5$3xhM2%2uHIM4v8*eey z`Km*g!LE+EN?zAHK7ihk_6+FRQ0?P=yc_t0F?5)StAYrL|HprQw2Jb<5^~yo+zsci zZGO0SR;b7h!5PKlAaFjvVdi$*p`OQ2mq!kGs3bZTzH7Rvc0>Y=B1VuK_O5C05dN2c zcYz}3&3gHgBF{bs+2~bFc!{%bdNi{lRs}#| zif%U!hB?hk)i~i3(MV&{M(5cJwzmiRi2~oQ`>Ka4FiJAN6N67a`sz&WeHGOnBDd)r zSE{h42P?SQrMQ>a$IEDzOg??wRX&2OfW{@nT(FvvwklI;9gw_iX>(7f(9Ag$Lk zI3sVa;?s^9RV2%_J||?6YwZ|xQW}}A8>nR{(D$yy&KCA-thDM|=&_ExXq$+D_KFo4 zdyYo#6bYpffqbh>q58$zKs;xiN>zmVyNFO-1}=}g7Xmi7D80T=h72_|XMFyUr2CI- z4VBt_N;0W~rgwABD>fKCLt?%6(Kwv-H3ejS*ET(=Lu_UGVyfc$L~hM)oUD=FJ?p!^ ztLxu$I`h%TocYN(O+L*zjR#Zk`s}ChWZC)|rjbIz_}D=<34AQIUY9sIIT?-BDAr`} zP33KlMG*7xjRBReg>$>u=c^QH@Fn=GEqKBay1BZVOctuEY;N|ORdHUwg8AoFUW6A1DrdO(cY58dYGh6D^)=WgeAL z@9quaNMtjsLY0^(R!Ev>%pAp-LtAoK1C?C`cld%BDp8|7Ba-i@e+<3halI2#+$@gM zBh z!ANPgjjDcdQ!406Z@)U$llQJI^G$q5Oo6*5u*kZ|i*Tox0?Vk{=a@*UEPOxBFsL)l zADt|8tw|b;C)!toN}5;)A-Alkj2hRko=k7!@SLG+044k*+)Xr#%eo#zAu9;TpF|ehn5tg@d)L5edxUx zNFqJr9S*nOp4^}LMs|Q@Op&`@epY(coQXmvt61~NZTrRXWRROn^@}E=N+>TR{G+WA z{SQ-VZ{4o%gzpqe=wfJ9{Z7_;Fd>QbVg6H`@SkIbe{yXG6-_QpyP{~P9M6pL&93>7 z#6DgBI2GB3BCg#)d_}S1IhwNS?D^;fXXW*fVEZR4kTtxNTD=qPLc?izByo@^FKfO* z8MvdMT9S<0tgRo%C3GzQbSiUr05>gtr^I?jVAO7uZOe41;B0CUrLC2R@O*EWk806D zEr3<_LC|WoJ=1<5-|X5e(C6&iQiGc;Bl-hrPH$3t4L!hjh$&uZpsk<|1R_UP(+eyL zVgro9`I+WG%86@*Pl26Hn{cmp;0XkzBbW%7^K=%~_Q<$D-B40s8;A;_FI;0pkLi!L zALlh8!H9q_q=lUB`V9#-IMGGx zg0gb`Ck(xA8v)e3M@y<(4yC;934*OW0jVFn!GSFY_>fw5|1|((FXTYw}5dy zXIo{aGU^P5nNYA&mzOi;L2=#Dltv#nEN&KVFVCh1?`^kFnDy-U+P)B55mG9U(*k1s zUHOA80N1Wv`;gO8siF4#IroLL04z#-j?}?+p0)2NDv^k7h0_td#0E%Bq~Vj%9@POO zdo=mQK$35V$NY;IL#J^jLl55>7WZVJamA04>I+aII+eXRhH2PEZbw* zv74m)uFbqJtQb=+Pn6#pB2G}op&2ui+}j-IbGf8o(1_#Ci^eMmcU)Jw9p0W~Attk} zQw*J)zpWwHYY&Jt9BI4G)qR*(QGZ}{tLTf}=iKfb;IwwI zQx2z{q*{+#F~R4y8POE|I&bdQwi(N+f#7M-t%n(4ubeDZM0UUjdZb47RV_;{!_@A$ z!9zuO%~@1Jdf}rS-Cy|@b2(CI67q`68#JiNlRK{kK-`d;4G~`@uFfH*ZeLUBQ1}@* zh+VE(kxLNIv8G>~g>d|rfbW0(QOLRV-PB~8vMd>lJ`aj>f&ZhyJ@nj+&3nyb4Gs)T0O0@NX8@)#X9yc=2?^|JSX)Z~#5Lw%r=Dnsh! zF6*Jm;wbf*I9GTNP0(I;Zd-!1OJ+vu2#$Qri#4p#-6rQ%T=RKnKAAELV|$akjfb3# zfpkvvB`cGAMP&)3r8|gK!LGrv)<>t_7tJnqCMMO0r*YZIzHU+cp^N2aLS0Rf{F0{Crp@KzR`6hy? z7Y(F7C0zrWsLBK-QC-VJkRGJLUUMg(w`Lf!COU7I^1zjs!KcswZ%!(@4TEGCKJY4Z+PdR4C>Q6m zmuF^Bu1g_aRUAb^e_5B<$Z)NjpFo}qd5f6ZJCwaR z5yguaWmFVnUc_GX0fz_@l18E>;f(^df1hj;8^NP$o0ziEey?6HAR3CoDd^YnGep(H zkaD|PY!7d+H+K5Eq`r~Hix^N(3W2^qVLq=SlOpU1(&Vt*`cnPIoxS%a=CqOt9zSPL z4PRJOBb%TNvYiG;d1gc&qoL zC$gon4nzw(jqS#3w{0g+@g%i+8qf!@6ec7L@1kuIU+cR^TsM@sT;f&D$}VUq=URPE zaKBl8iEbX6Lie5W89GBK=Hk?+#?G(rQMS^N@-*NwX;mUtCltv_~YQ=9~oV;j#hm&gFQ+*ktDYkk<(wA|&_(MY4a ziymv(IP6xf=~uGN2qZ~B7shjCDjlKP0OCwUfj16v!0c8w7j>0^)OWRm(cJ|Wq&Ux% z>#P^oPCJ}je1=0mQ;!s=8xy9@zf@Q1P8YRTT(exi;l43X6rWZnw?L;<2C~_(b9PmFlY;njJ_E6!AH&f^v9r-&r_2SsjfZ$(h?;!_KLa4*(L!rq?x`c84rT|}e zXar@c1&XYSjO@PpX$$g4JiUcilu zP4V05bQxCUgp6n&C}}+w@A-7!Q~8S;MN=BW9iM<IWeHvXR0hPI&G8szcqbT~8X_+*;R)8vX~{e65{m;^#RJ z1iv5clA6vA7CG!tH)H`xJT7InIng*lv<-)QU$2%&^cjCpfFWki74XhB{f6c_j|I>W z=0%l$sC0u+i3W}NKV1}(UfRpp==y(86F|y`Wb9c>;osXuOy7%~Oc~-%^>Bf#S9u_U zDzI2=8XMH#o2KsoOCfh}>`6?gnKKp@+`o7f9W$aH9d-TWM0>SYaN6k`(;JsQNi9Wd zDj)OgL|xUqP-~)Y*?Oa8@9N{R`b5QAgY8O1f4XdO9D}g+^^B5n;@qh_D1osjYLN%j#ejNq-KSFhWguHQRGQg26fx8OCaSD1=hn zm`!G>_C96(_f7!B;q*Y3*UaB zO)LAfD7iRB9JtcsR?Twg=0Eg-kgNE6n_P$Q*tHETy@9w5J@IBU8ewCdi*FR zgfcq9&NDEZdVij`wn?AUot#;!Oo$S_`SmW0R;{aKwz|+85(Q#slJ>X{GQ#i%Imo^? zCg<#J2QeN84;x=H;pz@+S6U4ZH+fDNucMGw@-24{i1aSy(bT@=@#rVTak_};>1}X;gw`v1`5)_6oGK)L?#ko<%7NA$rA}f6?L{Z(3CNqWd<;+LK}1BP`0$bu{9V91 z+4EO^24lbc27elMOIU&H4fyPv-3M`B_?t$uBxVbW{Y4kC!9ZcDXScQl4mGy3+;bh0 zs;0w7fg0CA9b<-?ZX@7awy=e}d?gU|p(2~xO}`Tsr)jpmESmuzYi|q@6-JNcV=K}2 zPHww&$j%hfN()}c5U?QZ^{NQiEQ?Yt2B<sj=WYcf%Ax5vftl$8sYpl=S9{S!`Zdf|b#jUDI2Hv3mmWQnoDCkFI2^CoqJ) zC9~`^h1RT+`-@XDe=SPR^EZWoj~|pv$deJTjd>9EBH2Z1akQJQ-eu2ZS;#fh%(`1< zTMd2bI^yRh7kN20WF(uylYv&iiVWY&c66=I<$x?4_ORcuG_^?``8RYhJ)HYdz>Mr{H}^^$pr(h0L21S@UEk3S4jN zi1AbHiWI3{uh!{C;De#rOQ)@JkuG+iYd~B$^tEvp?DbZsEFoCDTDOJvhw}+R821;9 z@|H;pe&_j;Y55$FA52w?7r#Dm)XX+Lv5{_oFtYC%o!Tb-u*Go|Sk^>$Dwc3L2ImS?OCKFjI8jSnN;(K}ZDS^1Hu z6PW$n%QX$;9HRhgo;6+S>`PcF!X{8Y9P|vlpr+P!;OP45W3AI>nq|T~RpRCTeD_CJ z{nR_T)BGiSao`4t>6dBWRQBYGbm+}~59qX?90l#@8TY>kOZkAPR6)mJ8hNEu<@$d6 zYo0})_o(Tqbg}Eg>?F!3?})Pwh#>#YZ|a3tE9++UnpjSUVW~~TTJIg-gQCGy*hKJ~ zLlQtjQS(jZz~kJap1BoA)qvoA8kc$ij>t1C8l8HoWUkak$1LV`?xCo$5Ve3DL~U7} z;S)O#6i({=7CWlwLD@M6oT$x4@y3(UV}+PgyUnI3+uqas3#Z{!L7v0rLpCASL#|OF zuX#UTFOVN7dT8xSx6@6F4ERyAPPnFHGh|4qoESDUiiA^!2kleLwe>f}Iy~uOw)}-- z#<=bFc*(P!bIuqNE!opG%dsR(Wr%v|azT>%278kqQ)uV$NLqtBP0A`$CH{=sP0oVv z?6K2CWm8NyQ%+|_%JsIrPnIBM3R+GLkF${F^Ih#_iYVsUX82JdpxP)Q(1pv#2spV2 zJ^A=xo}hKlQbDavVqH{mV178b+|a6qO&y(nf4WWw4g+ZQrokSMyv@sTIKH)ORg#A3 zMms0Wr$p)UvBUpWQ86fENsl{0|iT^Us_T}F7FCmP4%K3maUB0QI((Ik)LbW)jv z3SkXxPl?UlP;#aIofv5xD-Z@gQ;ocX03R}Um27CVR=mQ16Fp=wk$y0YE!<;qo6)io z6~?+FVS-XlG3;A;$ju5Munc6%rd><7263Q%Z1&8W9qsz^@Dk~+ri9Z~Is*Iti2XTu z`ZJf#l>y%hvYQ|0!VQjo9iF{u;l9PnR52r+%VKg+5rB?%R(8=h(|gR0(0pAW7pb&5 zwHJ>hB>1fb5HA(QK_ZRGD})vgOQ;@Qr#lJt!};TZbw5qUz}#6l2n5UemT4QmPc6Jo zDal-4SANw`dX7S85nBLTP3*4FoCc10aw=#4wUGTDi=6()yN|g|!8EZ2v4g0z(SacF z&uHRay?$p18a`@wqWFVKOh=z9snQpE!%W*SCDSHcPAflP7%6qd&QzWVNKL7A#JJ{D z5v9V*!kZ}_PCLBJIvb!_I7aQw$Cq&(&Ct&tP^7VjV#{boV_|<`B(aw$b^lW?^Z!bG zkaQu3eCa~)h7DSyvsw^2cpTTH_sTJ-6AaV3{HSlYW(QtGlPV+sz)}?nA^_wZ2(gLP zm(kcn#UyQDrEtMZ=`j51Rp-!^vIn$!?J$v|d~<#VZlWb~&2<&Kt5iQoyVF(Cg=gOa z>S_YA4LWjMR!!4I^toQbp<%eZQTJtUbBm7JHbao^nxgHlUFT5LuC6o#Xfi~@2z`pP z{k=l=r^`;VhRlM{sQggME516c6f!F~syB;J@U{s~EUL00aK9#OH)ykq88WbZ z&Lg{r+?SO8?%IJb9CUNF*loMV~sm)Fe1kRM28PC;(Jygi8lvR;WF#12RLfonrRMvi^;{E`#3%q9IUnd&P+|(w!Cgu@L>rb7pqb?Xfz3K z3pCT1s&48c)R!n*jqA*F+}l60(#Jj~J83gIr89u><=uNE zr#WBf6}jpxPikA+KgEZ_J-`y;xo~G8XuatEF>M|J?KkP}mq>36yT9NeG&#Y^%5hRr z%!^Usj!CV}72S;(H2dmZAD0=Vg2mzHc($UBy8i-+Q!yp^WGF{{ANoUjT|z$n)y?>A zJQpLjF##RCcM&v6q!Gq=RiCtgjG0};Vcb)B*?~6V*}syh|K8ncBD#Ym&F~P@Z?|Ps z^VJUI5??%j4xx(Qf{1v?VW|-ia40`#G!eK!asIw5Wz}}$j+vr%Z*p>eK~x9P>Q}{M zifkE#c*fbsrRgDB2H7Y^sTx|yWYEG&#^bV8`ZXXKqOqZ2d-goB@^P4cz`Rs8>_REG zg>}=SF<_^L86IT+$lt)14!|qrAd3TRrcw)IOpohPe~rprl2wq9K7T@0i#H2;wG|y4 zp}J2llnqMP7x2Z|{V|y2`76di!4S8tUCh;+2X&^76$-P~h68MQ)^ru-T<>l`Bv-Ct za>3A}CyFEjlB38*Q0TCwTdzJ|QPh8Ov28&|#A3fv28wGcV;9XA-I*g3aPdW(m!&)@&QG{@LoV`h96KU&sdo3CJDR1sR`(KPYB$!Q1*f|Eca2WBp$XM{l!@CoIyi3j=CE(h3wz@z_}6<; zS!o0%X?4!uI%(GukBMBqD?%nzc`|4!HK@@4mO(p#BJJ0t##1R$u46Oo-C{EahwH$K zKzS{bS*~6PYFyrGv&)^C$mfYY6t-nCkOD<0u>j&jNh^AcSc-@^xV1slJCrt;HNfoT+Bg>CO1Ab?WljKJOLpj~2&pUoQUd;HEZ;Uz zW)TpZkg?Ch5L#@oi*r85qd4u0rWC=MW2s;PaXVgp;kcxOB@NN*d@jvl;w@c(^9F7- zM^YN4>m|dQhD`oLQQgY+yO4Og&oU_&(dstF!5KmT)vALZO=t(_?YSPK`5%IrR;M!U zE^nphcZ-n@5-G`lyv->JR8!V68r)<5sL8$5-&%U+^n7gRw97ZDzNsFr| z%|LIND_ISD_Kf;PW`R@tCw;0jJ00eq)YboAneSiE3q-d32@SQ1up4xtGgGMaZxOI_ zbwWbK5g%SgUzOYU#>UM{F;GIp>-T$g zwl}B8PUf%G?i{VQS94_B5iGE=DFPbo@6pe3m_#miQw10GOLE53cK=YHA`bw#3RV4x z-Elw%#Ymx!$lQd`xy1mQ>{8(3faQ+Q`)Cej>moMbP(QI03_O%6W7A>>-hOa<7erno zk>Mx>yHp$E;oa@7=TRKwwo>}31DkQG{VNQi`8m~#F}D%U2WAU})O=M6GD#eQfVI#? zIMwfHX6_l>x1nmNljTVES6^|XN$miR&RrOQt!UQ2hc8+<^4~L&TcU|3bFeQ+-ofEL zFD`+&E_}Ct*9U(_noMY-c&KH>_P*0R{?6_J6^KK!Dbv5g5jLhc zD&ErE8+x#p8)m;3$TX%tax+gBA$4e~wbC0)uZyb8zv0$7-<1kNCMj1j3ZB+*0isYK z=FQe88|?m(9gL@^__5Y`;jr?drl|bW{j#kB8j%9#p4$bd(FTy*o?pi!eqWWLR#naI^>o%W4wvc2X2rXp)+&xl9jkgx;l ze>88WuhIv7smtE$LPv!1)K_m@T^8RnIsAaDQwZ~`%H?a)WKp>F+%(#UXzIpx;SYUq`VJ>6VD~0w$CB)1r8_Aw2;nY3C&Dl~Rs#7qciF z;ZHuzIoE8@d$s5q+g94M?})D_N{yxrsaS_Ms6BePGVsf7!dlOkf9R`MyRT~!>;>yi zvgE>&psu>355|*ge|_EcA+A5F&U(7mnWt>G77j3#fQElO7LzG$Js5|RlseuRIUxVx zTy>*WldaZJOmbBuex8}VNM~s4y&Hv1_RFMwvaKP1d8MA1&x8SYPxg|X6nv|;W=tLY zWQsfV{Vubl4zjN~G>}ZOQ?^ z3f#;e%@C88OXLjW zvJ$XMY(o*=Vh0xOUvvU|-(x2{Duv~%QquxNNQ67|oz7tWt zW?5zM+h#7Oo8VAfPH`t|!<=Y}NK9~1wra^72pg`Z=fv7DNbz=3ntF1f{t;&2ONCIZ zy0zuYeEdkxNlv+ogT+udjD9mK8pZ6P96?c;ZU%IpGCC<}64zDR#d&rUU7fzcB12bOE6v2ZhOYrE< zvVR?hRmYd;!YTy{GBzr%0H?z*G^sGKwKh~9 z>3ZuJWoOzPA4B{-W(kq>hbUbsqafNQJRZ5Y6v6Jf+q(XfU%aKlAam^}>sZABO#DPk z@BOHeKm@AZn>P0(o!$Edg!L7M5kI8p=;6ZR_8$so-8Oi6@-(ajE9i%rf5M<$_P zN*Ztn%t*^qzFj<9$qM_ZP-M-1Q)lW{v9X8W>(Y7Km!@}(mnRL6SR^9{9pMZ?1t!js z#Z61*WbOvC`GCuiXG39|rWU|D_uStx*bv~b*-F{R1I{{u!96#Xy+5T!3GT8M87w-} zqYUlByPMxsRKS5z-R{T#T8QIhZ#IFb#OkE-+V(0}9I5{xQH!JUh^Thrkk>RAxm<&@2i0;zzOQ5o!J-V;Umo^!ZC3S%0qvKK z?)M^{A>Lwx2FEDiuS&Tof1%8rE4MoTr6CS7j99Lv7y4wrqOc@jfQJeOJgH?FEf@VV{mSWxzNmthI-FMeS?w=4g&INfMF8SfJwORzG{xa#SD2 zV2arBO2>~}tyWxq;*v(yNBNc03%QG)^ls;>0*Rb%R*R+4RFD0vs2pxX^=R^lEE7il zJIC28AgD46DHIy7DKi zLiuu90i}to^cZXT44OqKmVfS%qC*Oazv9_{`$E(6_b&0G{*HQ2fP@q=&WlkpS~?QN ze4Ln797Q5s2s`F2h}5HB9$?W^ZWrqprDl z5fn!iDudUco!y1T#tzC*WTEoi_P zl|P^1M;Ed-Zn&TrYlbx)cs@*`!E7NELlrx@euY;hiqz9sI$R@JLXdDZr7#3)OQv%U zM`}voOntsq@hMNoE#*P8P>biCPG-kvO2CQERI!LMtGm=%YoWIxY%fWp9Oqxu-pKy) zv1c9@^3VRAG~*wZr6myd7qW^-wn!;8AOi`3CcfZt6aaV zrUihmhH$%co$2jTfJp}=5pZtyo-2DnwHj;~l$#P0U(}Ufd$R+IGI4UU#HPNIwAG_%adUNy(h-OQjwBY}>Uuw{;_}XL&$??x-hx2yR#j>3 zVMZL#B@U=gfR@Ar_u+D1Ak%!d@TEI}Cy|Kuj3kyZu>nc8)c_;A$CL?{UCwu^P}50e zQ=-#_s%dq!Z4zR5g)@=hK-87kBC;H`i#%I|7y{`4o zx~l&3tDt0B~BN z1U28bR?D5fm=Z337UO#Mqby7fP$I7bCzolcx^r@ zm}U-%Bs9D6Spmp3Z=Z6{i~W*?s&W3(dI(DI|7~gh^D_ODYfmr=c{q_>ZZRKsSBR6( z4vX&5VUp)i!PHsTWb^iN#OfK)2zvvF-3bREr67|@h;5H%r|SvB$$7cfHQ7jnsz1y_ z_ib1^9sDcBR~>&hKSMHt;R`UC zl{n{eGC74|d;t${WeS-J_yn2o*W{YDmNbnBQn)`I6i~_g6Bq-gb%_}KiqZQsHam=3JdT1AHTtW+FEQ)|MA>EX2$>b=V_#$a_HJKBfXQqUPmDCWOE`` zz4-r+XZU~kGjH(k<4rTTh4Fidf8vsVhK1h;G28!kT)13M{8Z*>>J#)7{`~u}K|MA2 zVSY6iG5otA&>s-SL{IOMWbQ$S_t*d1B>Kfh;8;>`3;rMO#Q*VEkbF1WLrC3@$bpe6#xTNrY?}&fPcL28(V2AxCC-Ney@&5iQo{zuom)PSaI`jYW&i@a8 zmh|Om7hA3rwT=Jvhe=Nzc-zD;V8;IXg8%jf4EAr+!WLw5-iZ7KC{A)a?MRCwlcfW2 zkz2_d0rLfb|CezbW!!TNpgEE;RM7}kb-KDg3&G%Dp!T&}vSK0n-@UDEe|?kke^pF$ zCChw}h=C4wn6_#8kG&E(s+`k;ezi`1$S%rg81FhG)1=f3` zzXIJ$k<9#SqiAopI{M;(NllJGE`hA2egbq8Q*^#8tI5yqf1;i{k35$Inzl+meVUw9S(!P-sC1nWQP29Arx#6aMhcz)f`6HuLC4Yu>$B3|Tn-^RLeZikNu{NLV~t#>c%4@=G<>>VB?3l|84Y9sG(wPe z`?E{1a@kVTzKhBZ16E+WY)UZ*iHFOuJ3MxtF+0aqFF02|Lv5dxZc}z?rZ0}ib|soj ztI<8Gc&S$SHIWEvYNC)*r6tcXX21FA-qz;*(Fn?nIS^d8*Y)u=OvPUC^V-W@2m#p< zzHZ1bdtz!X8i5E&z_;vs`0m^34twLn6%UjMQ4l5tWmYI!*osIXF5&8Xq?^%kv#&4yzTYg*qG2T{1v~O8^_y_bLHs#dey2dktFwm9*~VZX7TAWnt^k z^8H&@iyY=%j~rT^CJoJdMBY0-phk@f*|>(@rw+yXX%qzBR}W^c^>y^yG2`}8ftZ??z>k1YB{^Gpy3KM4UT5;@@%Og-k_6t7{wJWF_sX7qk z;xIOp2+L=BoNhE8F4m#_tZYx_NI)6ND&f_7dwTqKxAy4k_()Pv)0ihK75<}Wky?O^ zV<7+DTCN9*ACce2TRQucvkNytF4C|F5_bkRVGc-|n}5w=di{ZPjms4o)!H}sV5M{2gSR0fB zw-Us$mwkB@5!bJPUQ-xFURGizraZ6mwdmNjyCER(Wg;k0@6Zc zAN&-w;Ec$OLRfC2>t}1awRrCjC}_;}>G{3d;|B)nY#1>B43-9-DwPy{*B`}>I%oF> z3#|I-06?V>)oG_>v;QIKSqZCQ(AubB)WW5bZd@1pSeG0CE-J@13?|e>+aGdgt{-bg zl1UOyWpA|m0+4+;O{_-8BjMg+cN>eF7^x=4%(X&MYM1-{O-La!mbX}jZq(El=8F0+ zV`e{s93>NPzP!HA%*c)~wW}oE}huUaYBO?3}g5RJJ>xLd4@y2y6O2aI-S> z2jl9!qJZ$?l)T_A54a9Do(Y%=)f@zK#f)B5YLxa+ma*7Br|mf?t94Y(;(U zGssrH7hkB{$%<^e)97mb$u#Yk^LCgc#~~vGemFPWpH|te`-8eJL8VR%Ty_XV0Nj zr_yFip6Krr11-x41V=#MC{T^^Bu&Z(s7MpV@_~RrG0ClQ>%>)01@mSbf_Z|%%;=KO zlI9{nLz6a%V|76ISqRdj$9;i*8iK_dLZjV8I(FAV9$*k*u)2|)xfKj;Oocx5wL5~y z6len&%5%A!S4ROAt1)N=!Lc`+Z@L4W%bJtMX&O2916gV^b}a{SR8t=#d)lB+6%G&f zl_F5bDFE`gK?H8SQu$lr7Y7~-okf-Q-|-j*bX4v+6ekriOMJRZfkHOc=MzH-nAU86 z)M_i7L*pUSmf_=B?0DI#-gPCL8@FAZ1S*nxBm|t{Ao)E>Q2 zHG$k5NcfBC8985o|E<_@l2yq8nqEDQc@w$o>xW;izI$Me(9lKn{4%>go*|cF?5Ag5 zEymk-Hb&svUs%XRKfIyh}h;l9oUey+}CVzJB(5WOgW zQnC^=rK2SF_*n@kgDJ*}7{Kzq7&vSim`ebG1~0bL)$v z$V7ms`4oqsrQZo-F?7NKpS*W#xwuW9;OmAfNIE4 z+yrGWtKG|PQ)Q5?D^yO+3U0yGzQ;e~4!-72d z4CnDY{kOMo{f-lc+VSoRrcC(gJMhAR!7CIGa^?>gt8`7SAjE&j5d?zyEa3?o7q8^T zs7Wu;ML}=?dqz$O?^lKyN@%m(?Cld~5J9Rc#JWG&S_8BP;yS4G%E-R}Ps0f1li z6&vTjJgz@GPNrtWAMogxxNHJIi!~}?1L~;PaBb+%worgk%`iuvIp?rUE}hz_7F))M zQ$LK^5xlq3<;}moW{fIit&jfc7?3VHoDT}ZpeA44>GK7vnsf(5b+0Wizn%KTX*mqq%D+VUjlM4^g<3D05gGRkU#ae}K zjvyH(D9tQj_%obqA}~{nj`~u>q31G$`0G>wa?RH^-$YfDr7iVU>pWyp8exAF!@_=8ts~zO~H({Xr6GhrYQ}T^IHGf4cJjA!h#eLcKy*d^Y1nnN2%* z`nH2k+WMD=f$Z<->)!r4kir5Sa7r~xILI(}1E8>wcQKELX%+yl);W-Z(<3@&lb@lCPJdIAglX<77s0>Y80 zW~Kg?y9!^fBi+CmeE)A!%Mj3R3d{0L zVdMFRo=I1;4{7*TWa+9lRGQl4rc)fl`wSs#*lQFJKjn3BE_nPY+zvD?`yZd;ffv(p>|Eay%`~7TQ?5JCLA-98PBK}9sIm^90xt~qcxNy9ex_vMO z&m`4rkCvz!wV@d{$2V@`Ucs*+#PLU4w(1#TPI<0rVlS%Hs3d=k>1f09BDy(awkErk zf+|gaZmCg!6`w*TyvARU`Ine%w(-%xyB8MP`yHkCp)T`RrejjLIex5(Y4EM$4yC&J zRph({qm_t2D3I@&3{7F3t^B|@lFgc~H8H1=lFjQC={q{4T4~lsk;<;qr?FZ{hkf_r zjxiAKV~2!rQNUCzY{QuTF9$XddG9Oz+1XF6yB0|=MuqO;i^_4Eh^R-)tYFVZg{1PB zcB}AxdY>Z0;v;mhR00}jS^JfcZ`6A8S6EfJIjF7~`C$L&vZ{yHBCn+8$%-(#`QqZD z?Dj~P zJwRTE#N%0fW-+WyAI9I%h&H#*wdl5@C&2qdNtT{Rf9_`jqB~l4Ah2Gi%5eCAE>y?T z`^oAJN>Ie>`a!O!Pacpktb%j4TXZnTu2HG|LPtOnO2(=-HKKF4w_d<_w(^zBC?><@ zwJsf1A0#(muWj6j&9Bjl-}b#r)AXT`v*w)r1zT{pZ?g?junV)`G=Klm-^T1Ql9M(iQ+bxAGRPb3MixneO=!pbP!`Q`WQY5&w013Hi#V zQT%ageEfEoj_dxNMP~QSfw&)%3b=B{R5|=yarD6P8QF~2|B)&2?_(r#5oh&$m&E7TaTauqP!id269-%kAug*037&pi ze`1(tN?a2+f%{zoIFBez(Z&AK<;hh7%$If>FJ ziSvF$fAKad2o(FiYA3GT{pWOJ7odG7CA@rXHU3MUF)9ONB1^IGhgUiJxeuWRQ`AYW zkyc~z=jwS{5&M|OrUzG7(dqr@l>sK&4|nMa@76?U*@)R8{!lf(F2+d`D}N;Do`Y<7 z(~+#bGgt_0LA%F>xcu_}Z$HRQo8Xyfiv#y&T2GExP#$16)?wR-%`B?1L^j)DDSddI zS_<}9nt>SRe$0_Pk>PRN;up2jeYne!5`de{oo>Ij5^17b6G1{JIR%&?ST(r8u$x%t z2c#wN7a0CS=1V$XL#19m!jGXpJN0lmdxTL)ppN5ZQkNTOuCbFLwTq2+NK37HmwU1r zAXTJ5R3Osg@M($R@>o>yruS=CfIPctwPHP_$nIS5%sl2~RYY@HkSolq8s6dI)td4B zJ32%I@U88!d8RM=f4Pwha=j136lsU13KfGzU5`6yJ%Nb&j(7$+g6UroO*OUqw`e?s z$LQr5QZ0?$;M(MI7x&J%*@~uDtRLAx!s9pK5$g|t<$ft}?EhZ3v3#N2w~u-3D~9Z8 zW4U5e*?4f`L!41@)1|6T4ctut-WO>2Er)~gbrZiWx>;~bvAZIec^a)_`F4kabR zeI!q`YjpK^Gx!`Tf2PN^IKWabk0oUp6&{rOdpTsaC}90XX*Z0$YTdaa$gkl3U7^;d za?vJIp|ezMLYk|990}K_6l(6TgMTrZJaX$f>wkNcA?7h)CFz7XzHkFB-88c7m#EKi z3B<&|f~m%^A>(Z86y<)W28-eEZ34dDhkq=>i4}|_m@mvaxhfCJYor*&SDUhMy>xPW zHS}-)jPHeIYHHeSJH;Rjtnre(&0RW!UsS8kX5C4YO9B$yzK$Qv*C^k8XkhqsH0f%7 zhi3LwSQYFWWK`og_a71_s;Ip%f0DJAI1Wg6qvUB2;|OuFc9NHuwh~Wh)vSLaq~>VI z?~~kO&HER|XwH^XBKDtFW1ODWn6?>Md)dx>9Z3^Jt19wrRq5X<*w6IIz*Gi6fV&Ss zpiPF#41P+SSyu0m=+C0(Rj+mAFE`T*(%}leKEk0EaL!Tzt|B09{dN)*IeY`OEAP7I zRhtDbWf8>Lm$Q0ag0*=(a-Z7ZD@C+H3PVSLXO9*%em>vN+NZx36gkohzUB?k^#N7~@X5I| zpejfHdSc+U8sy8GT2NAFOXa&w+)Fgk+g#<%#a18ATFQm$0ZmQO#Zw_AJnYT>&zBb;4gWhN{~ncpUw@+?x_+fk9v0So z+_42E=MN4G!UD7YitB5!7fS0B^CoayTM2Kpg2>uH{HG)1viBQE=iD-YsP5DkXhww( zKq4of(<3llBRSv_#ZJp>$Wb+xClK*Ao!w3s{d)tWF*;8J&}L`V5kTmZ#&oe#HM!B4 zS%W)K9JP27ATUuuT{^bu?+%O`@xNbp-G`Ldy-%QbpWfPUcAe5(thR_~)CT!~AfV$G zYp~p+Gg8?Ekm9%R*r>g(G&j(@B+UDz5|4m=V!!P(oh)&i0+!^PfI(|XwWM&|gs-T+ zAmrgpZu~9$b&K7y-0j8%5FfHcS87ndSgFdoZ)yO<08hj?q)7EU9aA4iH6^+&)}4p{C{}6`{6XA~MqPZZZM*c`iH6G!xarp$RA@RK z!z{R?=%*F$|I1i}ek8@`2pjtG%0kO;L(T35r=*Mfy9Vt6KWR6&PxRB&I$M9ono#j@Xhb|+*`r%`Xuf{N)dNdsrZ6sx{9`;x zqR=R3R-o`6?P3%`dg>EP_P)VzY4!!+WoFbU1`u8RHrM(!&c~58AH)o%fAD)8uyMgO zx5_9?ZeBk-I0W3&k_}sgggHC^QJWJb{sgrD^Ur9@)Sj^CU}^1TKaA~^k4MQ7@QoA5 zhM8ahMGsRBL%!`cNBY<|fR7%k^p6?>d|r9XK+@Qe8OA$RdR*$`A(b{cVdI`)X-ocA zK@MsHJ)T^-Bu0fo4vU*xOx#3mD(8GNMV`N8QERRWaYg~K7~U; zGnsh1$|nD1uTg&jsu|?qm&$=pA!%e&;8F&u4`qqexFo=!^S_ajw{v}!Zg$IN zt8dpGjVJ=UXPuwO@lHmA#bdHz^{+h>U#=Md3kfc3;38_Ys-$m%?P7$x^^jE>cb0g9 zsylG+erzU3kjff{7{w?%v$6aScm01{s`cr6!19e1>2L~bkt(>RahYoLk(hS?r%_KQ zr$qw|W(tzl>#|dQ_2cmUtF6k^*dI@!T6U{I@MZi+YTa|W=dIV1)K3^d*AI$ojC|gW zd>#I5Ld_`u#a1^QC!Oa$=Cdznk^QSZwgYm{nyrs<4TAT2VPEN`1D&45t7J<=?TneQ zod++szr}yI+HwX6#omR>k8k$~xa>%yuP-M@UTd}(igyNYvecNheQC5AeJf_#@N0XU z_W0(IWH{@v#<(S3KAxIq(HU(Cx*W9Up1}htv&LrX&wl!+!dyOj2gB=-AVgik5>+x+ zN|b?X#%JIiZFToGA;}`m8K85SHcy^;CgSDDcG_~&6yszY9sdWUM=R3PRLf%NV&^kaL52w718X7cJuaME30fPZi z@YK+A7U_x-Z%Q7sBI$l$lX?A->;ZCOkF+BHugcH!^p}nZCgG3C@h~3(P{-HkgD0*p z8s4{L=7!Dub1&d4PZU6>8(}4fRv0dTZ{e!C+k!zl_?NPl`p$;R@jbG%a42y(6 z0!m2;ZPbeaetn1&-8~pzf8(PRWE8Ie3<3Y}IlfrvVoh6OAOSGVzZmkmt%=(hQux#R zT=n24|84QN4k!25Rsv4De$yl2$PZ>A#GHyh`LZS3Hxi|L!qu=iqHmO6%czkOCruT} zmPihaKet?x^aSo0%a0IkN%yTMauh<3O5Ua>l2H2Pfu+)a(ycLm7V<1s&rc)R5^B5B z70(s+P+Mq|Ea5cZ)i|>n{y}%hGul=U_B+?@8O{xfeis_@{x!#1aR?Bt=zsewqTNnO zcCpE(0C4`VV%M$Ph2&C_yf-P>oiNkP;;$%nFarV>hXA{x!No549Uv0nGmx%Vhwl9b zHy&T+vc!Fx&K=jII51}nq(7+v6ZBy&OaIf!ub^G9B-M|ZoiW>m%P0==AzeqiqiT9+XbG(qja1+Hy%ni zr0$t(;1C{KZ{_Fn+8IC^9q5GuY<0B@xh26w9*-~VVND6BPdz@;9X3gkrA0>u+f8h;l%(K)sc{2_YB_ zz%Bj?)nHZ{&+0A0AL+F0J(FNp)DokC7<1zqsZVc0O{gG$^VBXuuhp zv84Fucvp%U5%Q$JOUk!lEJ7ohd@O&v_Ji1#*KlkMt<~6G!5LDhKQbZpjXba{3g$LZ z+8j_%Lg$FMz3b$&&yB&y+*a70HYPi?)zXxkETmhf;yg3}LfTX_ z{=|;)Ue*Omwg(-`A0q?V6XeS5W=dIZY1B&CTRxz+m3Os*PrKBN3TzwPH4!sS3O4qu zl^r#eY}kLBWd42+nqJ!ImQMOoaZ;*A-TD7 z?$`6G$)p^Y&|+uR<7>v_C*saAV`j}O&l*j0DNCGd4$O(`p4a%t8D+mK^r3GI8l){f z$UotC-z%GcpHb0&R7Xf`G%?+C0Y;8@{>B2j84O!^Wc;gT0S8TW{`GQmd8at)+2kx9 zUBQ`4I-|DZuM$Bf&jpF@T^_7W?Vk5R-hO#S72WN1nASZ#L>~449<+$Q2&Ul+t{gL} zALG3JrocLkl%<8M_T_@zHcMw+rso}tbnby^uOeW_7h?VrPDwP7-`-{sLU83j* zh^F7p*JEy=0jE`R;(kI|e|XhhDWaXqGQk?bN*#sV9z&Yb^B!@KPuyj`_b2T{R((e{4w9p?=5HOo@c#E6Ji7 zXz!X~6Ag*`O-K&a2YPRe#){ z91i^%AW@h{8jav8maexRU(V2g5601Oa~Zaz11y)X#Sb^_bxbmm2-;CEPj4cQ zgYvUj3Lb$Xish#_jUGiP!m$divJ#!cHWmGGQx~ub)+nl=E@k%~`Ot85P zsz)=9soDrHUhbNw1obOy7fFbh%#ZS9s(M;gml3ADoY5)^=0XVSYwg0!~{X{XP#zguOUf#$3p{Y>QtYBxP_|>M&HA=u#xx zlvSqZX62qv?&xt8p_zX})_u<!pEaMQ5nm56lW6(NOk8Ky%%5A8hv*q}AA3|aRwsAIxjVweyEbmxT%b6UQD=bd z_$jAokYTNKy=O!){YR;1q`!%Y4va2a#cVI8;thc}>=Q=UYDOF$d(U_Cbm~P z2$KOL#wq*6C4RthwSQvF({~q&{GGd9oyv2*HL`Ilo^rBK;KAeb9!Q*?*KBr`_7K~p zqt*=sU5L7$bUToy4&gGW=SncvEOk_p+LKSIU$+Mf?THQ6p)iTuaCCk^5+7+rxX(er z+(EvV18Dsm84fHOr{To*2%&%=1%39f9zkijotJ5n#LswvUv$NHMKh-|@+C2I9Q=H) z446#;of&Gcad^ghw2jYXf?cl$(cQh)+%us%7@yB#)O!5#a1FjDJ#F;!ePICFZsCt! zRU#xl-$(hhaKbRcvX5eN$|HEzr(W2lfdOYbm$=r!@7GrYUdv0YrWI6{XHRHK8DuD7 z9{!3@B3GSuBx@1GE|UKlMXy3n`c0}l*yTAX)jHm@%4|QpCj#9I$hkr056MH~KioGC zxcvGn9{|w};JXcxC5H2YSnbP5~0r%&3-e(RF|JIbJp6vt9l`sYw#HfTC=bVLhog7 znh)FT(74lPyJ^LJUgoX6DM{7en*Gj8h(D0u1q$!DlS372I2Y=t4o`Xx`teAtN36s- z+xk}ZcJa|3JKQhHv7puH@2~e!A#0V56~__wI6h&g5cMNeU*vjB&_8XtB4K0ApG&gW~?v?gpH7R z-ANtE=AtTH>rB+iQE8|ajSkHDnm!{^D4iR<_T_8cD69H2MjV10R05Ni<4SR=-=qrk zuq6drnOFY(ZH;w>YE=^P)3b=o_z^nDghAbla?6z8dCy_tCK1|KOf6Qy*j_mk>v2Nf#eA+GHz9pOzro3E+GQ_ zjhze&-bgAq!PK6*1YeFl2%-OY2PjMb>xDE7>o$yDBZy<_ei*PAF-0(?!-qMUzx&OT zo(;7Y4UUNt$(Y+UdmxC^My$oGSuQksWji(nXOtK4)$Hz8(m}6WYDnFQajvrnar_ow<_h=QTWj$?mjMEo|+|y6S^! zr3)ff**Rvi`~PIY@+1J;d)Vn zSAZ|OB+||B_apNq1W*TsIc;bNPNCLA1gz*~1n{??$bXX`5qf4Kr_#7h*s}$llHWuS zC`AyEck5wT&wJLCRXn$xX@pp=DaZ!#0WXyB61rFBBd>0aLQl!cMvppTRayO!feOtd zg-y9_!ITKKHi`MB>fJF5xKy!j?Tl33s(%lvRV){CKVZJw{@ZCk=IOdAg( zz5y!yaM3KFtXr3KlKA1$C_*RP3UnRlOfgrfp#xYX>>G1Y``&CdJ#X}@;utFBuoNNf z@IS_-`n}EOu?FO;D#IjJnPskf7gF`D=qkr<1UfLUVB^5z>9Va7kh^e9y>R&n}>fw&b@Q zw9T5R22?qDywDmEXwT-JJp5)fksv4I?F|6E-295V$pTui4SZrN-2^puf_;6F>^Ki6 zY6$|n=LQM~=41xH)WW@L_YqRs(BYKl5c57d3%x&m5Q)C6>)P@~m^Z1*hS-u12)dx3 z{{FH@t(LrX_sY8Y&=0X^8p5HArVo#b6EGP|7EXC^fHBY5UCAvNEsZ;Tdr?^ne+X3D zudOaVLa4P6OwfElFpr8p;yUi>nRQv7`!&L#Dfc#TZ{l<7ULZ>+`1T98X{#oI*hO(S z;tlhmPZx6Ef*MN#=gma`VW?t0oz0Qq9!<_1*RCI3r+=YB#UU^&0x=QDy+M{c3md=ol|5=t&i=Kjk}}!Y30ml=HAMLd(Xs>tac)K zoAQl<$_+~jLF}4!5UJvmh58MSv)T_1l8L@Y3vLxAWl8s)08d&EaQ03x7~-HjjtZV$ z78~0*`Ur~ip?CjPY&YGdZq`(xEAR9U93LQL(}H7@3ds*yV{SPV3 z$Gvr#v58#mBR(1Mv0gnh83=mB^1tEOe-JIcMd*8iux@Bko9$1T-JsBDtfU}`16DE? zwIqrBed>-6Z*p6;}L?=m(S&5A1810 z=y7DgHUTj20LP!?DAylitvKoEVXA_(~b&uZWcE&I<{ayK|UXQ9=pYu069jB}~m zt%XTBZB~VZM(`~{;tMfnDKhD%#k#I7i7t47p3A741sKC47gX@>%uLKXQ~T2Jf6IR+ z5-4k0JJ-uOAD|~3>KlDOtyfG^^t_Su!Vj?A-o3v@?C(gtuh1;1-p$gCeE46X{0_{|*?@WfS0Fgq zXyUy9!W5l9hVtjZC@H)-D*k>Z6;h92{2?LHc_<@QC1ane=tNyQ!=5lfG2|ky{A@xy z-niW=LbSSU*%yz&D>L%0z~gdN8I1`;Z~~j|7L}4U8e$ct(=t&@ZzouP8_h;qQP56H zciAK)R7V4Ie8C(`d8S{=w>C$ooX%;%&Tm~GlWhC5kGv`*5f&`D*I=fC$8fQ37MDjK zn_kPitD#U6ma$y91*C=AU74e;rwCHK56^E!=RF27xat@&?>>Um;P)}DdxF$#bG;S= z5B9Ava6GI2Qm01CUFQIwQ{tojbEr!*e22K^pf|Nd`Ef(u1cV2e`!-5sUo_f{dLwT| z9xeh0d?sXFukmDXT*NNxQVTnVnr+2gyuWIq`f#_dZV9Ljs{xnFNYmQgFt6M^OeWUV zSWA7-F1KZI!CNP4b{bSF$Cf>Xe#nET!lr55KImK3AhQY+6L$l-&j_>=tU)=g&X_~5 zuCtNU5XWuZhHjw?7jeBA$u$j+4T;^bwQcI1QO`g&25;(;$+y7tj9zjFwTxfKPV zg*gfj?g|_kj$9wPizSbD29sn=I4xg>)a3%gTP1*lT!GuICS+GneE1Y#ib5l_)D@?J zF`1lN%}6CQT@dX!@Bj|4#d?}MvGvKzq%F898`Vv-1a`hYHtoHKW%?fl0L7y+vJnkw zQjX-7SPu>ejbsRlcn%A?dNqZyog#}?p`WhB>hRs9uF~A1@?*E5Jt4ANVcVY* zCuBx+-u&C4v&`-W_9|9AvX8EFUQOTbH(fm*U#+{`JL#ln!AgSk*td)v@Myc`E3+a- ze=XC9bkP=9UKQH5PdRVkFd*R=Ra4(70ekeqt9}*cy8)6xt38`Ghjh66<7|H*+qb2; zp+i3jZ48788~q$B;YCY?EvlrykK2}pp4Mb_LGy(@<}2Gf2B^8fVN`RApuVgOu@9Yr zzc&W0J0!kR@R*7<{cVFw!;0&ornybKZASp|7x_u_$FAp%^^M{SgroGX-B>fgo|qHE z>&-KW`VH0}$ad1QC>AZHDZI3YE_d0v6m8orWR9~d#VhnzxS*%!)LOZ@T z(3M~~F0C+447d64y^r~9!BTjuNnMh6@MsxMNG0kWw%6~=2)^c3k!)F#O||FAb}GBB zus@g*w*LQ>Nll>V|5bhGNp7ut%bTrIRik1JGAN+1K)rg1!*Kk)F(+uA)I#ELElM|L zrE~6r&;UgF%KV0H7)ZVK(8`~I+->N_WAHfnRx~YPQr{ksv=%#@4_E34yo#Z6JQ_2A z?v;zQ&#X)5cffzP`{3L3^-L6mzZ%a*IlVUWuO(n2^#jC5FHqeM>?;)zc?WM*aA0 z+O0QkGEeLQ>*u4Gct}vrj3JI@m9#&}g0)K#cy<+e=#nfj8opzi;6Gn`UU`H$_VGI$ zpP#;tgC46g26_?iwV=|+Pf%75Plj;u=}C8Sj=*@MK&Q`%2`*Wdkx3fXV&dBv+8R#j zN|E(&K4Fub%Dg!jHj7jzdYYs^?`Z$Xtn{Ki22%ermLW_ z0AT1!#_Nx;Jq)&yw_Ce`*^GC$b)^HS69y6sDbM53r`;n-3;uMls|d!BPxjGZko)fw zde^`XCR)Qa_JMkJrUDax>=j)Wz9onYb^z=Xxi?Ci_?g&I!-{axhHwpUMd}R$f$TxB zs-b87$)Sm0)FeH0t1e3M=Fe$vl&8AGwp>l`6Vn;`G81N(Ukl&Qda*x`?_A$H2-$up zC6quHcSA3@@}s7tEc4ZIv%KoSx@MKS-r{XeF4f4JwKjI0TSpwJeg{?48mG#AKbIyr z6jtIuqOJ#b^6Y_(&J_on=slU}xJ|s^Y(IflPwpAl&HN=pU0B9n#uhz_p0!CgGWf0x zO4zSTWz!uZU|aKy;>itFTn+v+I_PqxA?Alzshc^Bo2wT+ zFRO=>S&`tPxCNBM2ax6m_RPf$pmzzHOM>au8Ez2=E$tG*1-hk*Z)K|1n@Yw`45u1o zqFM_{rh#J>v_Ufs7ZD}hHyNJl=m#3Uw1s9#_pa0U%F22Y7`7R)`;H6&*aY9Z&)jnyS4a(QZo5>6M!PBQ88 z{0hzbLz_EB{L+3~tp-v)9*jS!H#8#=1&ZS%-M`_a9Ls*5AaPv}@@uanGIg@1&3FJW zQ0U6va3VWV(*OK_Hmx6}Nbwht4{t|-_rlvUFnY1w8ya3J0v)8ga37U@99^x|)^G$w zt~Y^nwQdFo#CL+k+5#}CRr4cHYfQk7wYn|I2+R>?&oo4Ob_M2R2$4c$D^1<1+pF;&jtINa1;-~~> zcby>t0o1LtlO=WDTSFQz%ueN+>>)=L$sBrWd`=`ef_2RO9_er9^_u`7RZz0#zg!vQ6?M&pu zoL>5z7z3;f)NW4$bMAZ_zYAIgWg$-zz*kbJ%?F<=KkN2;is1O?yoYiBTV(E`cI7Zw zWRtL@FZr)!07~_s_QVFBDGA#=(_P+~ZWzTY)hq@G3+I5tc_$7PL9HDgL)x7ukt`h*8THT%+WDJ>KpEJm>-I0hNmlL zdlg^SJ_=YXd``wP(abJa`@r&B>f>x9>9=sHtn)bA7Kj^6r3trCY~9$gwB^9O-(R5Q zcawUQfep`VCvs0JU`SKJX2&z5M?}@?I4?Dl_Tq#%M3>V{e$5xHvuk}i6n?=bD^BUTF&;1HIn&Hv3Yk>%zuf~*(ThVy-sTk|Jdoh8JU{g=iq4(Q1^(LBcn1La`4%k zzVTetMHvVNK2lw+qaK-YUDHzECaam;t+EqFu%3|%R>=nn3~3X2>RzJk4n^{djQ5Er z9S4SLd_xsYFx!a_=R?f)i|we{I891FedRRO2By^e+^0@; zB=9+6S^GQh!aw#b<#Z4hd!*BvS2`cG4%TR((mBy<>>8M+qealfmt=U*0~`7?#6F*9 z#ap6HN0+jqH;nuZmHAZjzIDc_7K{| zod>eSbb{}iMZ)T=^+;TGJrU&Ih&3owaJkhf{hG)G-y0rCgCzRK{OK6kyUB9+W=Ld$0KM*mN&x`%ZgCHlq$Yv*VZd(@qAdG$ z?PU^&^bUAZ;H&r1fdUp^9=E=c+8n&1GuI6-r&c6_=VhQHbC47*)Bs+#NvRuDZ#?iN1#^%2aE)3PW1;L0A++U?;{wD*T2l#?WJ)Q zFp2U_y6RG_dZ<^8NbU%M^{hUfZdD~jZs5yyzR38ed5#W~0`rt9jyzT>`CvH_axS;= z?kG%Z65rJXZ(KoIfi$`WYwfNST!?zgAAT(Gpkj^@Xbw4@mYVOMi;~Or1RivF?5Z^_6Y_ME9==KXuU(ux3_pG&BPFAzfDz*crvE8h!^y+_i%nUmKS}$b zwM`LsM7tN}Fa~I%wHpm4+T~l?m8>8RE>)o*fJz*N&11xq#g{`KO;5Y-y*d>BrJPr_bM`#ukqcT=?Af$q5Jl`f8iRO!Vd;BBB*WS?c5}UR? zj9?(i>twmWb4;Sa?3d5nb(Fj-BTiP{Nl=|T4-HdwMo zHx-uF)fXXqdRiN*uw^|>L=wElt`&3^-RE**`*LfIkRPt<^^mS@=FI;GSq^Z(-`UrB z@ZD!ClLZ{S7f=Kcq(+mxmln}z2WO*nA{vb5=FzURB;Mfo2)s>T6He&EMV8l&#NfaM zM-9pfDcWUOD)6ohIov#+&8OEijUub{Z|2rypgK#E*%Ivb zeJSTPRXo%*X+^NJGUddn>G)r~u&&p88{j&WjxJd_pSW7(P9(pCD=oD+y*OTKC9tB* zUzXhgDD#ifXxJ9eZ6(Qme$<(uL_e+i{oX%dgXtb556lEcyJ@G@tXTjQsLqQQ2E11x z3l{@%M(*ps8(b$67ndac8i$D519l-WcOZcF3cdbH$q|jdd^i6f`Qm$TrB0q$kZCX) z9lg?s+ZV*aa**g_^+r>btd2! zAkd`JjPa+az%ZXg6#2GI-1+5)KmlJu}L~kH2%+tLjIv~t1F6VRD^4X$-&ykT7t6yQhm0c3*~o7FCujx8j=>ikF3;FYS= zM#n~2msR3JcXS1mip$n0Vw$x4R`^$7az5(gv9lce;q1pN&2PP0Cw?J-ih;L#J?Ho& zFwwC;a(ueD;;`Vp$=a_Ama{D~zwvMr!-6Th6PoB|l>70LfWxP1lg8t+<9V4c=haE} z#92C!`i=kO1x!9CgR*t0(T4I4TV!S=l=98_e5Atbu{|uFhYoaI{vU%O*M1J?|2?$T zihi@FizIA!tF?3<@Zscp*Any9dA8$I5mnXWQ{#;U`+eIyb$`Yh_1v?n0WnmnCC zD;$rb2FpmLhQf&c90kgon{)08leQ#-GUUBV@VlS8-bn`S?%ULUMdQoXlr*wqwBOhZ zEp6GfuwO0B*P8wc20uKew58XSDW{eX0{M|$nX&5aO`#UNw;?K-ydxuU%62^-lh!v& z;44W!%x32{ExGt{9RJoI$Bk)gL55MJKO$|P&szEPmz>pXG|#w1M9kM$&lPK~4GMiV z_K}NHQ|yT?4s(eTpn!!kH}F#Ex9CdUPM`N!fS}-y0&uP0*=RATJL8^>rm(h&-THF# z<%=d9&fWJuon~I_vdP~&JXu9qP2_XzkLNvSfyv6pbnIKfw_fXNJ|24cCo z>C?JAKeXcjy|ty-hiiDwB7eG!Fv#y65VJq(6Ggi-=X+OS1wTFMr}dsp2j|}!A6*n6sDU69JY~r@`%Oi_|M^b^ z_zlDVbbzG5O2Uj^JbG+%K^`+3zi2-6Sn1bjS=~;mp0W*5%RS6N{mTrfPVg8jGUe6gvP=0Li~9u8?quRlL=B*3TneRF~g$%QDJ(sRz0d z#A(y+IuogrEat}xR~_pXS4>&!&vYSrOfmKGouMBvb*iw2`E-F8fdfO}VJxa$j;&$0 zT`RQ={JBKMK#zWgHjy(i2%AXuU|nBCF>TGq5M-~BfvhBO+8Nw%mP>g`|Psef91gP{cdUXy>O!vya-s|;F%?ioXYJnmNZSEjE-{AsLP-z1h*j}$>`VJ}CU z0aNo&jP{b~ZZisQ*!o(vYp9rJErRdlDw?JBWPvqS&yhFVPLlUSGcF5e+28pmfzrW5 zIXHjx>HNg;-skgGxO9~fOH(B<6+i#F_l;`lphtUNyPKcyCiD*0E0%iCea*#YyOhW5 z+KTMjuHuI~hwG5uB9Lj7to_hL2Y2_R*|*)sgb*H6OI}hc(z^8aq-IY;#EI#!q=w!=d?_<^C_-8297IMh7UZmfi2=ip~Cee?-u5 zlT7gY2H_k)@I-h-kO(N#l5g|T`R8AG9sjUVy|&FT09t5MkiQOrgwY5mQsCDakbYD0 zcFvH+7z!*r@Bj8TLb`Q%!I_(^#|2XPKvfL(%tJ0^6Uk3?ht5Z((KUE|Cm!%JGH?Bp z63Qwin7V{#U6<#6<4RAEC@@+EN`}xg3CC}~dZG(g=RBHa&XyiIw5y^5XAz*iMJ?%D+rPqRE6bb8W6`=FBZ{v)QBMz)fp5@vJSWU~S6 z{x1ECh#rNR9Vc15yQA4c31c}DQyoj<#}86p5vWT8L=Q4ab!`XxZB2>S8AKk+=t1Grq#L9_E{Q+n4Jdm zK;cFR_)vGkZkln2dse^(?Ni?Hzf~TX+epw!jBDpB=dyRq2Av8U*y#kWbYT)b9ZmG& z^Iu!CE3hZ~WE?_rMbGxrwNzeKnU3#nCpnVHkGk(yjyGPFfp(tYoJ+E#j&$Pc%;Olo za=+Eo+uqbwHT}x3Yj#}vU8u&nf(t~x;CS|yS&3A#CsWcvr~BE}xbakd3GNg^eDYVM zly;qiO|(XxG>GEZx^BisQKYTPh3E3hf9!hk%KyOP{M_8-x5f6OGue}<<3(3MBYCTg z5a0VYEldmH6sSsdH-olS!~J9i$I_~x&Wfjf>TfeG)cu|vc11XRfcAvXH$6Np4jy+u zIj99jJL%8ogQ@=?(%w2C%C^}bR~n@(5RecN1Qe8%Mgi%NZcyo#6cCnB0Yy3_7wPV< zB~-dQ7o}NX=>?YE{oM%op65B|e9!wnzyAc;Yw!EI=9>A;%x7jkzP%@h=T=^UDT;2r z82jXck2miA`Xn>Z+!%;fs>lF*rMDYPG;aXZncnr~k@#*k>oolMaK{v~*&JHa1hiP` zuIP^E1DGUSM?$0Z1~*lG+N!R980x)u8ugum!J>CgjLS)Qd71DO&U|&v|NbU~=ejoh z(*uX)T^`3Z>lNBi7Mi5nM3i#_N%%zEWNwEO>TcQbFuENe8KRoh5!?Ez0U#D8;RhQ9 zi>2Ao15SHopMRr!!>A;Xro8P>LKl{;Y8HUkS?0Vl^(3xgF{dMI$K`R}Sy_ zZ7OXt^jav8&!PtI;`+zWHHt`Gc$CiKlM3z9r4GJp8OtvRfpCNVL*r%XYa@de#6qhC zU4S(w_q4Zc^uC>kFzJJdGKXXloKS8V6|QiM?|V7(DLOgk|AyW7vxu_2z-Vo)dbNV}W%wqd3RXiWUX(b!dDGbJg1nsSY~hLvpDU63sM zNjvMXWxEeH{@n<_Yq<7zQAJqa2IO}A13U+#;-X1^aa2*3unjx{FIU-I6 zL#l^qmFnwag;!7}Eoc-(W~o3}e)yvBGEgzk=&^6zQ1gxR@0!xrpwW;_0zZ713Vsns_lSe)MfBwcmL#uc>8w$>S+Aw(Y)= zcF&Uph6(;Yu{7FN+FiL!4=n_Fu3CZ7#`k4Z8LhAf?4_fj1a=4zH<7d2wB#z)f+w1j zsplG@YcQ^dX?CDuKZ#e*NTYztr#Eoh#XXUf8Kpd};she9&1{c&05W%|;(m-hRA(dC zA$2l&h`8gif7CYhY0$%=Cj-04LQFN@Go-6J$pY96dZCLT5b1|Xr8lsY9fXk@hJAY! ztXpX-(~$WwZa9J|=n9Qd#Az(ryRwnPgQP9tJFIKAj*448kux^vrs$|zv`41CaOt6@ zVeb`Ua*>1w5rmrKtz(GE7qO4*%Ev3^kVmxG#}hz6XRq|Os-&O6;f@IFFl!ZBVRj0- z(ORms6n)7=&+ppu5#eA=$In#eyCxsg29C;Ons;BdcXXGSAPxFi-5yYDy3&TPXt9zd z!ra@wXlF2FYlz#-^f}I^!bTvPkelfI=YwF<{E6jUU_{X1rTabM@s+lnb0H=%(-2zj z`1%+6;3F<_>C)UJCV4VLfx73T@2C@zE4@i*qQ!EoXb$Zsa~xRm%tB{H4GWk6XQhMA_=M%M%~J zZgwZJP8nBPx^qdKR_INibzyIt^V-;RSHh2rG=T2}pB@L&?9-Ej3$Gs#WyAST^;{Mq z@p*LvfzoMGg$SjiA?* z8h97Tp%~V>co;Us&((a*6=YI~`}U4y-R~fW)@`}(MK<6r)CaniOQnqZ7jS>eio#x7 z^pyAPlcQ@MT$m8Syeta3$=@RnGv9Z=Upww2?U`l$GbMfh*Tce6GlgiOYRBpr*z!U7 zYTc@ry`tu0;l#ln|N1hAr?vZuQ>|M(TW*+;bjzrZ8|n=rj>Kw~xY)H80V=s+tK#O* zEdVOtPR(A$aPs^Ri(#$Jo*ue6xX0^VW%n*+X*Z9J9lUJNWCF~QZ=W%9uWWLr9ukL- z+;!|T1&!?2vBQRn>&xDtcoNgjOwJ$wjVv6i={n99t~u1|5(n8~jQV)8b393jd$)k0 z|HDoJ7jq7PBe&>S@0gr>0%O&HzBEfN4dkoIvQ$R>NPYCga+r9U1feGVcPMW|wABKD zx%5a4(N(t9X^M#*qo%Z-4A%mNIzD#mmN}Ci&A+C%de-uFF3;!NE^SyLugR)Y|IVS+ zX`Y*Vx7xjD3U{Ddj?@t%iN7ujq>Wl#T(nf+t=Au@j1i@!Q|}_nLMXYrs$U}zBHV~a zy5-iUc=C<~uc!bS3y>DWo^mI}Yzb9&d%FQVV(!5!>q~kNfRo2{@Rfuqd2p`vb7-?c z)SbjhWL$6$RI(vBvy(vLDB=bGi52!%H3BBFW>6Ue9fcP1$;-QPyflWTh$$w1HUYCj zzQ{U}YGJRgy12xb8+~3o+zU1Ci5$u4&>AX-{MA#^oG8zl?Xm|lTGsC z%v57pqI&b4QaRTkyGkf_>57LV0u~bQRh(mhX3Wl`kHcfKC^n=Q7~N~UGT6O`E>RDA zQCY9HnQ2~?_JA%Er2{l8Z4f8O(6wk zi71u$`BtUo3!8E}emQotj-*akW z5f5`I&6QfMD{M>^(M z-35Ff+sTrVAn!ubEBv~tny_|3jECG+rrkO>N+3WV;y6j=_8JJWb6RY3huD9`YoDmF zVFA)=uakO&J(qfDD0$zO1yKslyb{e{8%0ErrlaC95#72K?+GPVFYd2RGYh-#K1xNv z>hLx@V%V%c7eHm>cM)bbAD)nn=(GvywI+?K~R<4%3vUbLju8B#pl|qC}qA4JqgCKS!=wAH|m2L1kIhozw}OPjAnE4fXmcUnPhVOPkT9 z0$>%SOkixV657Lwa7;kxJCQNcq{+h553Fn^ojHAK+cf;kLR=5GZye@f=(VdYKO-Cb z@D9s*-AVJ6znZNn+(Av8)be$^8|n+VhGrDjQ~g8(g)ys5>;^TA7{r!YiRm8chR;YD z+&yHm-c?Wz=xWs>ycB-7(_}uYa2m1WG*{=gBfXRHIZcNLN-AMkW&b>h!?1e_M8!LQ z*^wO{v0R@`LR0JhPOls*a|Y&Ev9rV>-T$jMUJ^EP-x*r#VB5ld;>Cn{e_+5TJ?yx| zWBb}J=VJRjOL(lk@%DWCbf@#L@I6Q()!RC!trE9#%~i}yW#vYy6faRWQVIcQs3q;u z1TZH4?YFF$h@N5j(4nTHfzk)pTl$rNTU6pSY-$C@pYJB;@E zgltHE#d1q~YcUEbW!GlPSQqc((5WE0iEGHbFG+4m4!@0MP5;6o}9?Y)_kxT z++}aonews22kohJPi)9nMK}u30zQqnyN6j{F=~PL4IAqA>?B4p(GpCXH)qCqZKv*a zMn8y%WKq@W-7F`z8}w-CArYFm*xKeqU-04f@R>6tu~_p$_YA!T#Gi$Ars@pbMxW4= znbSKU(ZU&(l!Ivz@*|*`oiI-}90t!%Ks?pMrP_=C>%|5X5>)z3R{o{$yCbS=3N0T5 z22kmpF?XGF)WZ24nZQkt;Ewv0&jN)UcC)7H+~jC`(4i|a2wwDJp?)pXkx?Y1e+jjo zxil2EQ>a(XFrMd_vFR?|1ob+a9U9KnybBb>j(q-gKpVf(o%O0!vF&hY>A`4TIJ>@1 z$X*YnXO)bLtZAbb1imacaG{g_R%oi7Y)ss|-;{FTXQo4pdLoFJiH_`=q^$gmaX28IkM(Cr|8a=jW=EI$( zOFc3GKEf_=aob_QOzrXQEccU^USO1buuD6!axLzRT|@ zboHlaT-GhoI#0zUA(IWCli03%)@H*dFR}UbS8@OJmkU&j27RkhpRgO4ulF_8^9s1{ zDmlVg@j^tYf&HffDnVXe? zt=siT($22K+`B$|$RkX-=l55MJ;20d)sZ~ti)adt(wY@haY5M#m#bSYC1@u9yicgloXvfzZ^yOF6DvV|5LR)FOEm@y!AlHiy`DMWD zQFR)HCD~UkcpZ+5Q87^Crjory=#YE9i9A@xltYiL7C{r~Ut%1pX{BjzO>;00ZdKC# zI#aqm>5~d%dtYCBGX#D_Y;E~nt#-x5P)Xm~wA|OE87HY1viwmsv$r!Va7TgeRmscr zX?&oTxbg069$vOOL%EKze3>6UX&h^~d)`F3m0W>d^~+yHk6ePX@EGPCZmMkgE%=~~ zR-}UTLvInBLG+jTXT^?I95ORnMVE1?0)kc$Pv{3Kvj74b{DJnz#_20r0820dVlR^H z2b0F|J1%Zg1`sV@um(E7oMmTDgBlmGTovef@fhG#BOrj+rSIMb(30jsi8GO-@qC9N z?pNMs3cGI9U1xjV<7E9Eae2N;p3<){V)y)60KxPjBkLm@9vWwxui?=uDZT4PA9lUi zH;gKH*EZg(gjKG6ZYctJ+ z-G%~B+Hbv2iTPKN#qk;+-sT(JXg7M#m8ih>yZ~C#NhKr{SZ1R!2sqvOq7;J-x-W9% zTx>O=^$COkes%K!NYEV_3h`a^yXBU{A6@RLw1je*c0KGh1Ug=xpfRiGgc3jY9;SJH zIAiaO6<8hpj?w{p-o#9n1Jxyvz=M`cg#7Yuq=A`Ee|QDyTo(k%Yz$q|EcwK8wO*zQ zG4(nS1VyRbFNHmOAx|SX6e3Q~IV9RtH4ZYo!7!JB13v-Ne}MzDSBkL10Pe!aFvXRv z8s~LJAmah_(0WZ4_9=$F9cT$~*CL!TJg^Up3_pMs3OY2plih#e`)<2WTzjfB_Ag6i z5t>K+c;Cs_Ru1D6BAKP(F4J7)qM=H8OaGd|Bg{>Iuf^r?#bB>#O*>oEUB`?vS{SO^ zoM1f!h}^Ay3%n|u6WKmL6uYxw`3C5}kRRW`n61LdHF(sz2+sTHm8*9H^$QAunBzi9 zmpD2;Q&&z+E=yDo^h*E4!r-w8Yj9q(!ewyO2a7m1;W+YK&sHd0=gy8e=~6tu9c5)Y zK3AQmY<#0vISqY_h>~kkO|u(}c%H5C^~<;h=D@m5t^Z>bhX(6yrFplpdLhnhI?gKC zF)?`}diCzpYwl3bt+eNfvb3Uxr4(Aj_dvq;PJ)llhODri>zx{QVG5J`(jD_M=?bM( zB9$+IoREZ}7&t8M@#~ZXz_<1+x^#n8`s>s8Q#)a?eMaec_sbVLW0Z0<3u$Ag;o}uR zuL*-H`zIfWD1TLgnvM-nE&`X>d{3|Nb%Jr+vorhk_^mswbM$|^_y|R#ZwJ*5=wBv4qBzpre)af$ z=i>a`PxBEfk~{cQVM=%koKf4BnxLK>TFS8tOaja8V=R{!hE{fHmt?{ji?4I+zRQ-5 zefR=vWvHg0)jbjD)y406yd7UlmBv2UsO8M|j@PVTptLSgJ)hI9gt6u$c`FW9bpel< zp!qzJ>TOPdelk#`f!qE?q+C~4{M`}P*L-ci99q~j#V^cM8M`E;R%9yJVG}dv+bL-k zIoZ!D6Zu`AHzd`x;dl*ZDBgZRjiLS+CuCI(^s=5(%N$~jYKYTWespQxL!MRCaBP(6 zzW4so|TDoJiyMH*g+dW zJrVk)me2-IPR}DJaQyeEhiMImrws&t?)V!0&Jmud&{?umZVL?^Lj=K;oDY;EAv`sv zN9NZ7A*083*;SxlZLPaI%{Y8Eoy!5W|DZiws9Y$H6QwU~m__q;a4~;-e^Q^($GH@= zfVliLAGymHd})~&;;^94HzyT*tg2-<-n!&Z_P1z>-yO)0N1Q>cne&0!NJ<=~Qs0FkN)xDvN7gOt^aK1tHjvK`}vP|5- z{Rbx0n?yOw+i+;InV=|@9G2d;bxAFS*a(86B%yZPU!m;l)K#QBwjB)oF291Vy9O$MfFTMbb|Y;B_hS*7Sw^%c>6NLnW)+mb zLWCYaZMY6cBrl9f-jLNlBq`Fr)Fk|fr!&?hrcf^;wN+8OsZc@$Tb)@kG2&5#9=2em zjYi8QEhgg8t&|&8LdJ=A+OY%Y``2PytaD-hI!*GPNoh@;3yetd*e+h3=MIQM{O;Wd zH(J6{F#An&_2XLiy&9k!R=NR zhr6BaDWflw6|jSJ>W2&mbHX8X2ZMP%iCpo$-Ml)(tTDR7tb31vh!}cmr5B72TJHVm zI(U*7n*+3e-C#iy!gBG77=0WTx;b?Jg){2Jrh;4^4j3%K)mtKg(9qRpaw`X z*GNED@3Q!+2kB{vc@NCzBy{{cw9y!Is!Ug4gT|D=3C&LJu{mu1(yn&enGoiGwf&A% zdjGlwqw}v#yI^QUkNws251t1`{$fV|91%S^L4t_m6YdKc-38ZOm)i(qAHRw{0h`wW z(3wrd|8~mN0igA%lv=X1?|flPD1S8y=LD^Uc!{e+<#idP@*0iL(B~D)^=XinX^){z z1?=FNzD(pj9}ha>C&7tzeedc@Ocgmkuc|o}4$h95iD$&Q-g#o$7W!m+sTW>wYo#7!9ZSb)9FQFy3$QhI4E9h~JY7{I zXBJTpdF%!`vr1%cXH?#8Fpmd4St^ze%XTl@(!%jxZbta4AlhTFpM`pxT403qVp?_< zksF^kKhxi#?B5LB>5t#EeSk2$9Oi4m!><~qc{&YQ3H%<d7Mn%*H;0X8lUMi#8G6<3 z3M$$^%O*G?!**9xVlR1JjxLN5hR|{@WdZ1Az89H=d@KLW;Dq}Da5y6K1-*Dib*cw& z7utnFbkvov#a;Nx#AbYeipw`W`g)&oet6;r*3%*IHI$p%{>l{XXx+wfXA*Wvn}Asj zH%r>-U8J^!UNj{ zG8L6x(Vuj`wjt+df6j64)!xVmH#y<8D-2TAoMZ@IDvPyz26C%>UmF0W8>jq=h&D<5 zyMxcEfxOZwYCA)Fb|~Mx&mayqorwQ`vs!;{+28M=PZe8{@dDF$iKk)J1*&N4V_6ed z9wCppM-k*-?4yMXZ*1CP_F`g(H&ZksyApS9dz2HpTC{cA>O-w(uUv?)H_Bf_?X+l@-B=#V#SDeCm)RB07898poX zNX=Xd4J#}^Ssz)1co=~2%5-uxtjcvQa>K0%bHj68srgL8ZVCRpbQji}vWM9~h2QlQ zi>p(SQF(*=sXnCXB-*PWCLX4Uk2<-_ zqHgP3s{Y(+3bJTf+vzU5>o7mY(tc#*ZlPBB^2;8T^-zwR3z;yiU0&2M*%O$+CE_Ag89)ik)EGUUOfD#2hOSObYV%;#GmBUs&} zOfTE_;@rthu_KZs>k7N!s+zRo9ASaUxIMwH-lPxgP-|_ruHJFeT-J13N7N4mge_v4 zqW2OrGv7ryL(x|?U(rH}anhFjo%!`cWI5)J2A%J_#E?RHDBgZy`tQrsMy|H>`AJ46SisXDTqyMMlu=QkU&3SOo*cCpWfhex0~Dm4z)Scf zUpecp@?@u}@5-48BhWchn&uoV0)H>p`EQ>7ztrPbCL_(#!JN?Y+!(_0jX^`4x0meo zk;W(P4j^!$gg8J~}0Ckzi&7EpK$jt>z%0;A1wy5Q}*f0_STNc^WWCqJN2|@zJKx+{{!d#wF&>uzotCT zblYphcYf@%t$0^+wiT;IO3|4HKLYtC1$Nm>gzdpaPed0IV*8fAi${iB5ghR@g40FBl0pJ}ClD`#5i znTQvO??2m%O~c)nr-vnSb#E|HcuSJ!uh&d*FnQEmVzKn3zmVJxi_Z<4aC-zU+ln+F`LT9{!k&unn3Vo^hk#)%YN^7ZfGtQRZ z{!YrP^V6!t1ty_B5M38xCHw{Dz}+?_W+B1~dvyGI+%WCcLD4Oef3&55O2-HUn2WZe z3=yy3aOU~u1=zOM{%*K{Nq913J(6Ue7?~GpA^q&cT+d2++Y>QWyq|H zZD7GtM#V__w1+?_Y^YVz>>t^Si#T<-zIVy8QAg{27W|IrOX>{uK%L*&TJ-mD)>cC; zRPRRJ8Xv%w1Tzc*FBsPU@;vkP?_=5D$KaEEjUWSPbrv{fp&ocVsnU_e|JhhRMrgTi zne6;16@0E`aQ#fzMCpHB~mYyiszU~PZ9qdh2l#NGaM8$}jC)E@HxM;(#}40)m4wta8$d(AjK z(qAAc6v}olDfM zD}e6!^%}NsQ|+*qkx=`lo95k6Aq}a&y@@n(?hcuS+~&uBrnXLaI#dB_UBDEl_Wo-W z^IeB*w=Lu{&qZq&cOXNSRhu&-5{Qz&JB|k$R&LYXw){C7DQeA<*z^UHky zOuKkrp(ks9|3~qEBff|g_Il27QU4!86^)ZNU?_99a~t68?SH{Xnv~?fbqe}7cl4-!iV)OcVi<{?a{Cso&{KfzK zKU_6|&rk0yET8|GSkcLML@W9Jb0i78b>!F>;rUAw@B`;^8xhw3;-AUl#Z2H7GV#vx z%zy{8c7vXb(nC~thVmb6BN;Ow$Ug!@V)@QN7y*HgG&|Nmdpe&`a^PtO=;#vv_zGAj zzj=6r`k#p*0Zu9)Bu2+-|MFzXc7UAFtC`3<|8T`Aao_|HWbvwhKojOG@EsU3u*(Kl+#eb@%gq#b~e<+AvxBv?<{RQry1#?eMDJLX??>x8qpDp}N z_(U7Pxt3_oUJ;120LQ{7>N>-7{vCf*$G>w~$gEBtC@v(N?+@sG#|CILJz9-_cq}-z zCkKsrw@i2bKxAAe2mK=~_1}4*|KaJ6fr)1fm^*J2Kb`OX)T@)DznL)j=ji{#ZOj9n z@yp)4`T57hiY@{AVMOVJ*FRhl=cLCXJrnPrD8o|&K$hA-@9KQUm>%xbN|w06NWgY% zZY5~|yN3!WnI~s?zNQVd>I>{$ucJT%@$!=5v0~&y*=wC@P#+fwg^a zELA1nLEG&yQhcWNFahF)`jDqnYoJj$eJ@inF|1RwKzdazn^9@w*0xrU)O;+KlI)Qa z5D`NT?i(6UbRBLi0DXJHWEVQCmJ+WyE^l^1pFQwbsmX| zPAEfaAS)N!$_bCn9$f0!PplOthoE(Y-FCyQO=An^+^yGm27hA4Yp=bb?hx^w!&JUk zQRzsl>(g;Or9*}K>Mov#pS$8}8(Bh(n>3Lm>&2poc-yXfmC(5FMXBin}>t*Lwu@ZCfAo_juKdlEe@q}*Os1} zih4#5*Q;JGjWhE4^-adjwC^Ur%i5RH^$a!I z=!MUsBFCX!9QC_btI-oyYfJn<^U*8%u1fvpOA>R5@f5d zpO8IP?<$w-t|S9&sqY4QuoohYX_}J|T=9?FUg&;cqdP=;liMhGvgmbg&`mD&GDn@F zmFCMFp}Zq*-1d#a^^mn|u>w1|nbI&@EYgH#4EYZQ_Yo2at_AlH(#ZRkg(EgoPteCZ z9Hs3^qK9uJ-Rd0Nlwv&=3L(L=iO<%jCHG54O521F*B8W=6zsiojlRv&x;*rD5wYs8 zh_U)4U09HR*R{YpiBrG7$8s7;~*o)WT+&EZA_zk3)@MQ`q#L1bAME=~bfpn+5pJ<2` zwn<~QpW#1%yszfCf0cOOQAyz78!+m7EhSQ*5b0iXs~w(!9Fv|%o?y@28=7;e-CC+g zraAkIY^ciQQ-$ba+eU6ju5>g36hw<$+a#zH%~bMH1S#`a%o&{OVfHac6Qfps^co+0 zVM&5cibV^2i9nBHtm(sfpV+|0o5fA!@C52rD?D4-R|M_LN((OgC9SLxDKCs0`zHEO1-pZ}!PSK;?{K>pY3z`0P1cxxvNrDi*- zV;D=jc&EOmd|wN9G6rZ%cLLpC%Fu`JOBEqrqFs4b3Z&UonThtN7RTL3ue778!PQ?n z@U2=7;Nxp_<^{bKR72V9>9SKW>)>aC%v5k=-)XSwbF16cZ~+t|2Oh)pd4fh0t85?Cwd(9ra>O{Q;0MR|?*lIy;%w z1^wuBC8pgNvoZ2*)I~T?cPfeQeNnrQ@vaRp`7L&gmlzR<`w1j!I_1*X40~UG>{-1L z_-qjytC;Zkb~$wg!kBZwCJ;(TK=bTwTkH>-V_aaG}&Uq7Kd_93hynQ8r|Zk#bywl-i;-qeAEt+Yjh@dSstvM3^c@sF?>dKYVhrQyA(E=kb>Bb%ETVgH@}{f(Jt4hvP&Gdxu53FdVX zgf5^(uavD5W$C_Q1aBt@;NI@~OMJ`c;Kqq=6cx1m6JVBL5ECXd36$(xPckTagS?2jbb{b zy$vXc&NzohoVrKBMUunq`EVkQ3mehBE&(Ic!aNqrsYxuQ(;S1JDc2k2c*db5?>jOWShG|U}EP~9U?Qp|NlF=K~b7{rtj z62I{ZWux4UPFTqZ8nK&sJzjzOYCXFQ@n4zTuL@T(ww{8Q+mL{Z2Pu$Bg0rWUTY?4`;B~(+**+W)_kWrpK>;r8x(C zri@df2A5yd-<{hVJ^GZmw^C{lnNF8yKT@uUrk9$&dGF13zkjD}IkTc!#E5570d!<= z!(P$)0k_p|*>y-^QEi(xNoD@>Eu#l%Lpyo)V8IoXrC=vYUdoTw4)P#(%Eij`u=z-+ z;b5EEHR?N^#Lw}zOQ(*oc2%0hl$XtH8JKVFG=eF2MwZ5H$hXc_;Y8Zsu_ zBS}gl!Z2vsKo69ExpX)+L49n{&3t+EwcnFGX|oTK)j-=Xm?M4}f@q?CzRKt@n{;vC zhfQ}=-R51&zVgypeAGZ(Ldu9IqCw4Orm6xcVe7j-?&ITm6hhuzV8-OCoQyF^6%Fma zmFfr*i^IziRxZh^|AhIT#m^3y_<>w2tJ2l3O8D4aPyAq)k?G4{u^7r>8y*46RiNo0j3^pQ#F~4%Rk96e{_l)kW#?dfTGYda6bQ!fB z>$#O=RNx#Z_$p{wXew8B}x_TfJ|Tv8~bCC!m4eVPsS zlF7>(MshTpS(w?^NuE<|aa+<{bhvTNHf%K^3fW8AO%vH0R zWW(T*UaJ6d*+|3DEGQ*$A)x3~=wMiZ<)Y1Q9E%{$Ig$XONw~n(TFAGgY8O|m&nK{Az&JwKk*@k6A*m$!M@}y5dq`=%OSNUI_|8*mNM1qSSlX)FG}GC zwJneI*M3x{rCg(7i#!o&4fZ?{f}vZDg%G*Yk?C$GkC_x1o9aUI+e)zo<`ox(V`6tD zf2~>EkraG+0tf`@RSGHZ&HW6$60!E&ULkR6Cz2#!2${s40ZBt~c=tgsDsyoY(e!oe z-|cl^q@nZJqyE`GpuEuUKOfl2`lhGSqZd)~X2l`%zH5*5MNz3zKTNt^ve;ANx-Y1y zr-!3QA&QzAwapRLO$nV{cK|tEY`KwZ@@uGi(Y{~c_=O4MFv%BFpnFK*^(vSm;NH-# zbRu$;_z($mu}SN9Ju32&N}_W4#wa-zUaW+F&+8(p{GxukYckiRH{jY?Bx)P1cX{YJ zm5~enbf9RLL}axR{JuXmS!}|N07WTz_)aaQBDESQVvowS!$p^TWwh20XwQ)vr<=Gp ztzE6qIPVI@+@q->dFVe56!G?X*7InDnj471=5qNrVr}o)FuVw=|}dF@N%t;}2#67rldy$)qP8mZMn= zF$V5|NDZx1vJbr}ZnFi*d;zt70pU@s+~i}1)R%gUpjeHSE8>;U^5CVbAPJbT+g$Ov zHlTy8sQ~64nz@zl5?mb}D|MvEG=^F^OxZhu6&VEr2ncc;WO#-_*F@g^24?4BSim#5 zNdXAn4^jFY|MT#WgbbjF?>%v#!b!PH*7NCk{RkYNRA!D`UpOXFXr#mPjk>@g+8>K8ioPY&=DvK|%x-dm~4V5^SLP^Fy+(DJY z;nbbhl(lE6euKEEYCe1@<8jL2YB{yZP}NG(E7oX`7;7ZQT}?x0_cFa+lEA!old*#d z8LpV;+lM_I-8qTxR|9U4RU7r|Dr&!^;ke^@I8&#fq{RFb)x(#itH03^FSv}D$tF70 zPwiLFW$oi3_Qj{4gW)2IAVV`Pnl+C4d8Z`@P~tT5ROD(3V-ld<_7lmDOAo^NpkC1G zG!ndr$x2dYo~REGIIVZDo9R=Oc?x)SSSvkqa7DJ2aq=C=5E@oDOYdH(; zYHyMByW}*G%ujP0D!<`beqT+@xc!$TAV)sfgz&Z~ePH14EAR-WS=&#>SpWcq!lR%# z9(SFOP)#irPI`yV5gJaTdXVQ~M?u`fa3p5lv^a0Kgm@&X zRtZX@P`#ommCrqvDhHq=1UJYi^LOGt-bJ`_74v4{(VLsSwc(4CDSd9`!i*ToM<^cx zBj*+S0nZ@R4ub609(`YY=V$`k^vxyhGYsZ~gY^?lybf|vtucONp;hSayA$i{OwHT5 z*{|B2Q{{K$*P%n>j_fy%kc^>7iaoTV= ztu1!nTc0TqJj6HbGrJXMv2_yrqbyw#T-rA~d_)b{QvLVHy9H#$(sbYdRX5U$;1UD`_4a<&`Qx{To!IT{o5(w%%~*l;H=PX|ptHqE z)`CE^B`QVo(nRVp%p7Cdk;oRmyE-wEhnIj99REx?)4D;%_p(b(yVk4Ju}f8*E=-D5 zWI4~jb`~^#GvB+-y&QbKTh=0Dq#HK=#2tf17EW7WdPOlMd@G%H#4mNXXZ%e^LobH) zC|)F=qPdLXNZ1qjOg$9(^$xS3lx5>gRTyf%66zJR;rW4oA<#s56U4N$q-Y;ZTs8~8 zKxt0bJ+HR6_0eUqLu?Xd0yy!OCV>e*Irj6c@atqrh3OY)@Bd^WExXz-`~YS2ULL%c z;z&iDb(6QKwtfS?Yb4@oX7*c9L+C`=^*x9Q$Hw~-G(-onT&G!ha)d20@Nbb^zwfnl zgP4O?udj3R_9$z(x3mpn*)H5dwaV`nPic5q>VXni9HJ~Ij>|2X2-T@Q%sAQZ0~ zG)fcB*1A4IPujXrx-PgL)Xl7zz#UV%6i1^nNxosxTPZ4?xiMpekJv9s|MaN>`sFOw zO#j-)9`hl1clXYG8v|N;D!b$vV$Vib(-94*pC=Z=w9xC2qny64L zJbE!|AYBf|av5->MB1PqK8@@E?ct6)H2CCynkz&4?VX}x;BcpsYV7Ok_YdoFVmV8$VejI>AG;j3BU~xy#I|1_piSaVGc*mfIhd}QX88hLj_hKB> zKnwM2o13pAlA=O13mhwWauAV1C(hCa=ur;M{wmMPtg-1p*Lxs#mq2eNrf#J+1sMAF zU+FA#WZ4|!C`57-7U1(TNMbYGFke4X*v{JLEo8F%h62ow1SNh(~kiYQr2U|8Z`w~08tMm@Qn!p zfd!MXZS0X_0N1F^VBQk_2_94>w|*iRZS{kOYx-pB-wO1*!5-<``JRq^!R2x* zKIogE1z8zE-?LVo(z0~I>E8Oc~*aBH24H#OFBh~}&RfA&= zLk69@_s0ue@v9lu7kqeCPZ`8w@|O<4GK>rLUqm1GCEgyG+64liKOv&3U?WEiSIqDD z6}}*tWz-uoGd=lnV);6tQu!fgU{iAEL_BRKiZb@B3ky$DE!j0f2GwI-3iR_2gou0w7MwVqTu0T_5qf@ z&L8GD5|$$ppiGbY(QGcmA}-2Ucg6U}5(Zui>qXcMJg}dV6#C{Qh%PyD4hEoiS$XF% zM?$yUeyS8En%u^t<3(;uT5ABjvv8W+=P;hm)Lm;d zy0-gkMoQ4XrwEO3Sh*YMigu!F<@_znzp%p4Nw_ev1&B)8#jtd_Y38{8HhF&Pn6@x4wTB->ex5Wzj|Zm<)xN0e?N2zO)yeP{)|y|yoeT#4d)c3aQIJp^Gu z&2mg71&8AZw#gSFK-VUG(~$<8_n#uJ4x^GWfLWx|wi8b6yEwqB3r|%jUfVq(aKD*)>W95(07pvZC%#&>J@e%SjC9Ioobjv%54kd7!c+S6h0JXHlnmX> zoqy%z2G9Xob#4jh!GG@Li#gyB1OW94tqh@9SZIpWCWB+zQs0}v3@Mmf7{8@CNA>MF zXO|0l2$7bA2@B@p@jcSWb@YvKk@{)tRHo61D|kz*6Zw=B5xn6 zPPQRjf7pZMM7)>uQM^(nkIf}JWysj%fs zN|sT>!=6U=-&-ehgJ22K1ywvrIV9d~1$BeH(2^5QYq0B9W@v5I50fx7iAr4ib1nr0 z%|o3EP(vsGGcJjmQ7MuY3;YeKt7Md)cP!thY}KyV`Q^yO$#IlVlHillxNPWBaNFOu zVbJzJrc5sToVK2;9GfOg@#4HVyBSR_Fkr^_bstelh~-HnaI=5C(lqP`v1J<%hFI^q zIYi84gJ`m*{zd(&%f7g$>5B|8P$lV20fP$b=@%}9RwA#RKr&!7tC=B4_fdkGD7xZB zS(4d%N1M!Fx5-7Ihw1m41rsRJ^dY+shMQW9K{L1ufz0Ld=yKr&#tF&VG_>g=P#ks&bjbItv@_ zaMT}XV0aUpu^4DB{S^@SR9y-1_ijrC(M1@NqAiHuzEML9xyuLBiQdNi`26t38PD41 z&6T2Nw>8EW7XKe-?;Q?j*R_q`dJrWMghYrMAtZV)3DHaRPV`O;27@7zkVy0rT||u* zJvtGc(TPqNqmMoq#&=1$zxR3H@BRIr=gu*I$l@zd)JY)0(Mw}8In!d+}Y_B2f;zo%?lAS#~2Umcy%^mksfmE|jAgYfA zqI*&=UW}^Mc$rnKjZbA2YQNES_}O0m~grQ-J)87pn}=2 zvTr`5{&K7Zf-BD)ubifeejr0R(4%6#3b=1KI3wCk_8V{V2PR=iJ(l!RQ0w+qu%6h{ z_W)*40T{#5x{5;_W95gk91Lz}fu>d+AqudgGV4x98z(m+jG-QY)g)rx|NbTe+n}C$ZncyG+1E)x_Bbs`+fi8 zXw268tlmAX?Rt>lqUcIVXO@2s2@iL5*|IuC+a}2YsV=FrnO>lBw_c@;bQ;J53^YeX ziPRsrU57NWg6c32&Vu>=_ox zAY@&Evu7brz_hK4Um^;mjybraZxt(nRdJtQC-;W=t5lbGQCEI6zroUN3FP+0tuS*~8(MJK)l9nC zW4%C|P0qiLzkgNgyITtB1H-D7T?432wifyZi$Ib#NnE%@gTA{?9K3U4F4j$vPkcH7 z9*Pb98uXDpHX}9nX+Npgo>7y*3mZqVAsWUCuH)~O+GvSX&Ue{i&h(l~slk)m&rB27 z8a6vEi9OC5~#HK=!ZerES3RjeZ1wqG%uJH;x zFUS1U5Rh(D46U32B`#1T5p)HRcXoq&3;Ju%?jd++`9$pXToh97$7*I1Td?-T09ISb z3Pr`mP?$6Z8rA>JdJQpRpaoJ00UoD?x13JTzFFrBL|Z2guSWzIRwpP6*cqe15jL7xi?Os~(2dzjBP9V{yyy^XUzn10;$toGc2wEV>fdOIn85Y+QI!K`2JR@&cHfH=C)Sbmwk( zs<8J*BTs!=n=~u>q9`DI0FAa7yOQ~QYClY4e@zkd@f>}qt{fdt^DqPg)Sm<5D`jkc z0tdcEAarn3E_7O&u%M%T++0LaO2MyFVTpwH|kSu6*8 zg@e}H35Y1@0dM$X%KJM2*5GakI1tBasA?ehEdqg#b32Ld@7IAx+)}QDh{2mK3!(pH zucgEYf7nYcHkgKYY$C~o5*T=mJgSX6TC?2r6Sds7WvM&Q_+C@|UCBr;i^cInuDrN| z9*SXVq&rqRIP?4=Q7a(oT+Lo@1lor`tD8uWq{ND}nMvkgB-dyGiC42nOw{@%5;q)8mSK){f?(lC#QGk9?Q&EeABHeeUU1M`$x!{775s_bQh3W zYeSg&YMVeE>|XBnC5lY>3vHayy|A%R&D(vtc8-L2*jV%javM}2H|&Czx|0lRJZ+as zT#L!cS4Pcfek1mQnS`%)1-#p7d%&{>pvjY>yJM~q?r0{#KdyxE3c0D4+54;ME#Wn#7*s3 zOnNd<t1j*DPes<y+m%UWzEVPT=dmj{Ia9a8Ww5quh_li!=F@`I9zug+r)D>oIE|=qhBHH z0tw*j^{01Bh)*a~PL>K8o^n40obAnr&Vyw;+g%>8hMI?dzsMDm4zw11n6V;LqjB|U z_LOZp6XDj|Kt91-B}&4bzeMq7Tv)<+9xA<3kAfLD5(^t zDa0s)%`CSAr2>_?^^fmg13_T)cpvvwFMO!=lit^xKMyiH+i0-$b#<(On z`aX&~z1rR6qTRTCw*SZ1?(zN%Fm=xAxYeaHO^T5L1Er_C#!G_-fUP1UxXkQaXmX<~ zKMbTYt>2uqbzRNVT)I^hx5ktCfmrVTWpM$bsA=Xj*s3qQaYFDTOBgSp{Jb~)<*Lhs zD9-^9k6RNj3Jr6p+(6l{u--3ylNzV%6+oR6^){Y8=TGPCcmLkSBLrlO^bh90NF|9| z(cV;VRMlqt+Eo8ct^hdz{>YY}2C3B_RSxolRL0+O`3Ac&4gz99FtDq>^%MUt>0Y10R?5afOGbpt)*d8os#HKoN?yqR<*5E4^ut#Qw==3Apsb4|nH2zArE za-v_kQ};2JBpBpto+1oAu`4d$*n2-dof>|7kfRyZw4RC{6q9?!sc3lV}PE*RVf*8dEPi(OlAe@ad1E%oAvPlKT4Alu5}6&d#1@xcB{K zK+=E&H5~*+&yt2b85C|i6^#XiEi+Xx@wc!wf>K9IK;g})mG7-pXa^fZE#^%a7zPWQ ze?uXEVJlF`uLD^&eYI3E_Od0et*f^eXWI+bcGHUJlDa9+NEofUfIQnrzi1IjujQ|N z_IJLKJc3Nf_XRu&jrYHIEY_|J#DQg+a=3m6U$$Nf{ZCe? z(HheQVSd$asj%b~vM}4BjD{Q4Y>oBBXLX*>L!fU+m#uBQPWG#20fy-&EVY?OW|b6u zaAt31w7xNgEY#=iZfcm}B!Imwcr7m~v0AcvbaJ9=wHvnq^XL&CscJF?cWG*KC;>hR zf9qQqKqoTCGvtcPLPFQQ2^~p?%|deWCGUe5Vb1Sf!YFEU;!XYJOni=15QlrZrtB2$ zS6xR>iD~Qfa-KniefC^zq9uRw4#p#wWYV0Ed%9MS5`EFr;n^JtYxla~^qgD(u1K;5 z6@&%;iF;nLkbjuv?WH~KT-^s|)Ci_l237hwH;RYecwnSnz8ekQ2^T?SS z30w?_)ykNld@!(ZO0%J^I?Ey0dXsU*u0os-6q#@m_%3^@2YP%&Z8ua>tY3iuQfHNE zK{7k*Z2cY?M`GQY&3|z$0l=L5l)X&@s=2*%xuVrGAd_7XMBHiG?6kV6`w;z|&6r!&B{b2}_Ev#D`273A^v2!!^24oD8>WatEdMT|fe~Q! z-t-21LU_0&<_6tQwkL1$nStKBh?c^fL-EvJgg))<>a!-79W;^vuE^0Lopxm8HUFC3 zzt8AT4k-|%Fz4$#c5M>@7MK*CAAYt*T?kH@HwyRrZ>gqVY79EqjQpaDR2-t2sz+`! z_wu+J?qMG0J^G{gt|Sj(pWPPaO7c80o3%(4>bb5UwJ3bLzqs_@7W()88wfHzf8K?I zhqMe9Lp8chU8K2QJTNPjnQ=djb!(|u`L${Syte%C(5`=2k9CM=&cfh^7=ys)B0sx9 zmK+wpxZ9nKSkhezRS03=EGdS)_Fz5QJ>HaYyv&4}!h@*lI0zv;!%90;lu57VoblGV4m(HJs+ctE=-u+EM_+Mq_|M`ntsRH-q z@K~R%!oTa2uU{O*Tfb7rf2HI6+s7PYcX_}oWT9ObuU|^}$`6Oy*8v?L50BM>wz+>l z@IUw|Fq7zqVlYN8PfmkQ__CV@j6TrIsfwK38{;cit@)1@o=d(F5=(ko0?aYkd9sv! zu_J~r7qa%n6i4+^`TswU@qfRzuGx6zSx=w^!wbr2kod*sLL~p}mA2tN+=8f4@wdXAC+bd+mziuwQb`S(hCfRB?Y*Oh1;gO!jTg{rCC}{=MMk zKBUYp?#Gn^8TJbc$lz*lamJXd`hT0~|KM%_nkeMS<-KbOkGOxK5}IhJ{%AIv!_e>W z|7^j(?`Q@GIS1XbMb@2x5xC>U*Kp+``g5T{+mjvQ|4hjvA}@p@S&m-3>axI3;l`gG zE1Wb5Uv_Ew4>!&ra4E+E5|sA96wBY6F5&zmZWc#|veWy#I&LZC?0Wgc7}G3y^;TTD3gbS3#ms_n198x$8Cz7e$a<8oox zg)#;$adccXf%yYY{Ck(~T%-{>m+vlZ7JKuOt-*Nh&%2BC?OOl4qWpi{fd9{@kb^F6 z^feGYIpxJ&2>f_qmmZ^f5sylo9*X1$3y|~aak_MjtOp3`vtS(g$yzgDjrRjIPkhY%y&_MhT#hCfh^k1j> zTPeVpF7DkOKZR=Tf3)zN(ch+jn|CSo;?)4{(f+uZHM2Od|EKAf`icF4wknDk;Pfk} z^0BU4{Ji%6_a?4ieuKw%75^52;y=>2=O0$^UsY(6H?!-`qQa3cf~%U}fl47oWW?JY zF?Ii3k4Y6=iGeIXQh*%6OXsqLOEg$kFBRPXaxbKeE+1{=AEHGYc;m()Y8DC)B8%&6 z`;fF4YFxXxY$^w@Su2WG7PN`t$x>2)B@1hAttQh3mT|i-c3ex4@XPM;@vNMR*v8M( ztcug}+j(1N`pDi@2k*BzT+~0EaDDOj8wmV?D`Bwxwg>X!lTDR5iYktl|BFx83CG$f z^!~1?kG{n0_G@5{O<$BKShbqN)P!Aci>tc$XFXj~nd7m2PK#vROVA_nQSY{qb=pD%Tj1oF@0jOra@tje8{3Ti=QMnzXBN z&rho9h-+&lC#i5Y4Q$ogo^OfT6c>=2hit|{3I$Z>zk`*4@^}Jf5sHoXI0XK&vH7DN z*}aBVy{jIcqN^}bHzkt!;EeVffAep7x`sDseKdTGoTykkFS-N9a|mau zf5P6eg)5%S)Ra8tgzom<$vbk#u^TTf(aKj$dW1`v1ibCQ+$$#s?erSHW-dS{^H;vZ z^~FZf2k&x|1xM8e&nn`rM&H2)tA8;K=E|(-6?5%BxwJQbOA2tf44D@y_tg(`3!^LR zlT~W?S8v}gEuuDcFEIjb@Vf!ySmPfp?2n2fAk0n^<#)q{=>`2y_XP)QR7CabeN>tz zk>h2x<@V!Za{@%yuIQTm`qAn6wGeV9M_eWrIW@2K#0r5NxY12~MCHe~@t?B|TT9Ls6&e!Tpxl-)c=wjX}?MPPPFsZRRQpiqi>>iop zT$AzHj+9Qqz`ECm3lOOE=2)C#RFvbmGp}q<&=ub!xURr&5(V`9p@kK|_gY(K0z9@^SJUUha@e`9lUn)I(z$GI!jeA-`bexcJoC(u78t~-K1 zr2z(5zDyZ3N>;>=FW?#3WnHFx%D)u_-wJ8$2eq#C{X@{?!iv4Ee=dKw1Rcy<&DJFKy8 zYl_xRi?ZsDgB$=OhysR-b;mTRdSm4=VBM`v z#!{QUyuex&y4BIV2Ty|Ej3GvDx13B}zX*^=Q4zJ$bIIiW>qf;5$Jr^T>1xO##1HWo z6u)1;0)x z4cAnxvGJsP*yV6qY*;8PN)UL5u?lkn9mug7nVdOIfwzY9Ej!Wh8AgE}ZHeH6~)-PEI@Eh+LGrBKmBhM5|WWq+dW6D-@CttH}Oj5@qG2+{WMr7t{yHmmy zF&rQdG6fW06f8vq_x9H4Iz{2pB$6|3qM{xdNlbN*0a>^Ew45t)aaTE!Pu6GupaF_X zTb~p+1=^RiZSvYd{q)0C0(t4kz2};+IwN;sxHoGXeqQ_PBAryZ0Y5?@ybtI_tz)!` zO-3}^x{g>b!q;LXJ2+Iz=n4RMQPWfWP9SR-Nr}GHEuQz2GUuWN3f}8c@k*g_8@ILC% zZt*0J00hZp+dw#n7*{Pg?GD~U&Fou+*N7ZCwRMfzyCqNbOuSpsQC+50tx7Y|0#2f$ z9wT_YU4_!Vjq8)#L)nrXl4rgm%Rzy6#k62uz}!-+!;lhK4Rro^tvH%yh^?bgzwA)3 za~68WL??=h0G|DajHgHXEyA`4F zTxRQuuGNHwOmw@Y@wfghTeC-|L##y<7M0i$`>S1kc8uR9Qx%L{KrIT;KZ3jMqNxS8spG zw*s9#kGe0#YTJj^Y2>~68EMteQM)eHA?niboz$l%`iO{wd`Dxv6cOQgG`D;GPpl5X>tD{&&*m{Pk4CCwGeiIG;FcDkk0cjF5NkZ_6Gn{_PwXYsE^%A5;7c0 z{lKTVj_(XlA@+V9>XkyFYkELOPXcfEu}6NCPggD-O6!9`srw3q5T={0Y}c9kAPMO7 zkb9N(r)0Ay(3wl?94xPL9=|uy*d*z9Zt@zXnew?eNFka>ZdO*ud+h9(Gct_N*E@z6 zUU6lE+%SG%2rlLbK@SX%Ec8WhfHUZRxWRkw3cF3E+P=Y~Q-CgHKPUwwxudwIDc$n< zuR{Y*juu}MbIH5ls zrU2c#uB{~|!FT(>`jSOsiW2$jOG&)K=(X=f#-^RRrcfr(QUgO`p#qNH7yT4Ak3qB8 z_cX;-@ka#b&iLFEb^q+QU=H0~_by<>@z;P3H!|@h;kLB;T(w#0onI$I&F>}@8o|Xy zo0>F#^QW3&7jW#}A6x#Qbv=#C^+eZ5;J1Nvg-HJX-TNiWsNKYl8$~S$0p`tcl z9S6%R=!EPltDHx)5(VtcbT*_}?n~GNy_FRMe{)1{qCf=t-82VVq1l*Kx5Ral z^5H!5RyQ8s<-btRrQ?$XTpZ{fJmnRo7MC8RDU8@xY-lcvYZsfec3n-FgzbD=jvY%0 znA7KF8>gx5t>`hrv6Fi*W|c9{p60vrNWsR6YTBB_oyWRIMtEzjIO9&Yq?g=acKy`t zHh>DCA#ZjnXsVFc-1pOFtf>~iRY@PqQ@@ZiSh5?$q1$0I3$<~9OcO6SVR0tg+ z(xMu5Z3cQmtpT=k^{fx+X*%UqJ01lAE`5V{*4=lZ`h8?3(_d9*N=#N)hbzpjRt#32 zfoi@k`GgsYR+g7Nv45C}FI$rnQ*)4%B+wDa6j&CtvVSJwuPoA&$UY zqCxzt>E^Phy;QD;AHF_Tgs#Gd9mRS<0#iYH{~H!n$^0?SRCq91dHD2Jk6HC;&3l-4 z&v(K#mt|$AqzU|JdqHv%E|s?{b7}3FoiPtG5-2&SzNu#O!I)MCjc)I0)R-=?C&8hk zP*y{>yZMd!Sy#Es%0U&D%A!tg!hQAy-W zm9FU(SVE*-U?pb_`BU4%j9;Bka|W|jY-$(c&*D;7CZDAGGCt1<2Yhk)s!hKQm^;Rz z+~RC6Z(%Vz$$8I_R@6C4IhoIRv#~f=ImOK<)46PjEv+E#m?UX3Kh0&<>|N_^R7VTt zdQ)4`G+Jn~=kcyJNtRV8tM!PY?2M_2!PdL7O_Q7bjqzfbpG=obJJ|C;h3K5_k0sH` zqK;F!smci=L;7Sl03y_xRd*WZbZEA+)rH$FY~b~iVA9Sgu%v5O`B1rM0jUkGpns|I zN1@*F{Q)_S&U7rlWREiS3SdT8op*kHq9oMBd%k*TUjY43EwQOf+ac5B)H)+&g-!J) zyZuILIq!+mE{f)SdeS)b%VvHVEva#ke<>QN9IA}7mNzcn@;(pCQ#NY0^kQi} zjYEUl69l1CM3_m#}|O-!GIJ4@-(I^m;IeBHGNk&a_&qy^{} zTH&MlfhSheW2T*Sf>u%C1&DqO=PQhXhwqCbW&MLxTh}bYcUP&%h26H31`)A%2kc9H z&Ua&XXE%h6bB_8t7s*ud!d&S2G@NTh>TMvou~mXDG4>R4leO!&d03@ATVv`xbA7~X z&8y3Ooa5@d+x(xvM;+7%aO@w#HKW@U$3=I$UQ*@wmm&OjBKgvIpQLj6G%Dw6&q{1= z4K!v(>?iHCxHNWct*R+~zMeBliE$W9d!$cQV9bJ=Nj0XboxsDKM%5HGzk(AKL{6hI z<=A(3-_T9vwrkT>NK4FY=PNtMw8L&D42v)$zIhcx-8NG!u7y~gI{`;SpPc{YayN}% zyNCx}C0_%>Iek2*OPuO$#Itl^2m6}Gm?#j&3@b9J5b;BB%5_!v^qIrg!)eGt2)@t< zTK=b%j>040Ug-2|VuaE*x`mz`2~c@~;wDYB8il)fB2Zp$B5Iq3nT%j@5ZERNgF&~w z*|ocp819zre%uHyM3vFT97}S1Qa9HuN6HpcZwj|ea}SFz3-i_53ZZCM#ojuh5os1~ z1G3bt@?H@?Uwo>hm-L^SDZn9T^Ee)(eRT-1fuGx`zmEsFT0XX=6n@1>Xchg+(O%iJ z$xv=m30Lb(gymT#@ejk=)+u(Z$fqxbv0pH6?T^*M-+ob>Oc^MDqCXEI8n1w!1;Js) zw&|bnZ`ZJabvVU~WVX@k*Y?5484F}~Ak!{F+`;ApUppT0^@o!b#36hsOMI^Lm|wE+ zAKMfe`@>=GK$SGFa#swy6?Y@1ZL+kp%c%O-LaZm7V(%C2t}aZbW-AeV1D1L~boLv- z21p9WqA2y&_7q56Zvt2-kZTm~&X6?HOs!HbAA z)M|#7S8l;@KDwOlmWaeKl(4yJz;}jlJF*2>}2@`g6I{i{Vw*{Dkm^lO2bn zo&4gBXgk+7fKYd%*IgUH%|s6erVnzB*Vr8_iw|J0gDO0fo8Fqp@sh0|JailCbVfT& z#S)_8>d&b33+Pn-)B-&we1BWqBwJOSayT8mGTWV)=d+l*?WXePs^^;y_4c*O7<(IA zs_(#1SmAiG8;4Z)3=c+o^HYL{SU>h9TTYHv5Z(zOqY+R9&=lA@qmzMPH0uX7JV&9| zh?VcUI@W7Ml=(lw#evxq*#p#Z=j^zjpESYx6>f!7eqetZar=vSse8DErfi z@auK&MSwn6iw(P4Tm4r#g7gM5UZ+@`5{rb$9|hm3nv^2BHC!?=l(cc+o{oHdriZF& zxKYE4%v)QQViZXafgS@jfthur!C<=RZ6<4?~?qs!;d8}Ua>M! zN7GQ!QDE$xSRk|@K8hwW?f7inj0P9AKFbF7M4F|!`tJ&8Nc0&?t2Hd;8*5nGLLul~ z6$6D2ofaE#;HHHe1ok0aChcvwhS$(+y&*}p4x*x4#a0PBJn4%3XI#=_=!P1pr**s8 ziydB{3p~Vi9};9PR`l|p?0z0S3tm07P0zJ<*qhz$UK^92wxfW*eJpGF^i(s5G?Ay* zH7|k7!~T&?cF)n`6ZV8%QtvDef@%ht_V(n}6`vyhLNhl&zvxSU zpx+Q;2(6`#6H8Dd)3Wp&3TP1=MUv2N{ruU*d35p)X$223#|jrjDCBvY@2joX*wkX) zj)ZSq`H}w@R^;|^=QEeTf!uR9ngM>9OEX$2ql@sWET%6S8vn@+P+P(Ed>yu{!z((H zB1p5(HEO^d&4T77Q&;4s{-{(}LRo5Tp`m1SaUm+6Rw`E-ibuQ{e_I%&*Xi+2->*Rl z5;gz~CxsXU)fQFoK3tWm#VDXx6YQFmb{FmQCF7uqs}-k+7scGh$EjEE@bqvI-C#}x zu2N2)FAz&uE%!?wG^B`l#FC`>uS&$ezx}9ZlS#m}pWJ(+LNIx*i;^QwA#8nI9Lw8Z9Qmr<%kN5I*i%W`g(o_<7$mAyl3Jd%rg*Qs0+0@?Q zXTy?@3ieaM(Z+pOb%0L8z%=`z><=wOAtMdp+;tE8R(B7J)+hF}K*g)t<+j&2>@+FQ z;k8m6YUuHbO@3;bCH%|C0jk$>i&HN>V6iJj6KF)rG4e%xWlzDC$z`(A*r39BjjQy! zh1fkh(aI`w@`kb~7v*@t886Kq)U(E**F@6~HVO;USFhO*;%X_yH*j+|2+giWAI7dv z9lfrv#b-eDMz?=4Fwz@#H>fldztQ*$!Ja!4`)^NgT``e)2ka@=;FOUB3LM* z6Dd(&yLuM@+RhW0Zv!yWCi$LBwJjCZaPPjpavYjnIJf;fW_77WU{12-#GXxxUwP1B zC^uKkh{LF`m9;bhme+hW%_#6Cl%I7Ra4X8Mh>;3CVV@9A=tkw)&lPcclNo5~y3P|18x@S|onkz%QxDET2@AcId>8BpKrEsyDRydW*?qSFPi#R+WQCmM-qpfK-!TdZR zW;`5djlgXBC*C{bsc@!wXyn}Ks?rp_v_3dWs_1A~`Et*1y)yu9>uU9A&1JO@dMy2A z%2b64aq8RT7dYD28>O$K(^@Au%g9l1HFjPV z{)Q|jw$@W|8m-vzG0{UjIBTy$oElWvb7GrN?v2r}wTzCXVUo)l~knov-w9u6ZFgxJx?n1 z@#L}>0EB%<84OW59e!jm1fuujR>^jb^mZb~?Y%1OI>0q>cE@}3Q$YMkK&RX3SjVTv zu+GY7EI6Cd8n5SvB}*LAdXL$31S^@y`+#<^ZM!*g)BoBPH0E#rFt*QA>eqOK|2I_| zi$e>qy+|t6^#* zxmI`)_0)SeQE&Fwbl&3IC$LwK2_OjhOuxBC@;Qw%_GjZ-ZJG^8VL5TbATZKW!%D|$ z#7}tlO!SmaK(gw9;R{2JM9I-L4Y!{d6?Y3K){y}Z2Zm6zq?nX-%y_)t_aKDL( z!Pox!&a$aY1*R30GQC=Y{(z%jG^+~XO=X9JM<9~-bb_8SnQCb>H(ra6No3&QUoAb} zP?6ueNn)AI)&RkVG8suXZ6D>0>6#SgvLc zn@!bt*t30mhhHI~Com6*jxT8X)d%+Fs`m*-NjQFgRpQCuV7|YrD}}=aIapobR{d&{ zad-+0i`MEpnuSRv zU-A9A{={yyF2#5f9AC#OXj9Xvxohe_&em&K9uEyWWuiUIrCWCQSsbt*y@FR;FhHgV z;koiLXx3|&ZsliQaQ*6LCe??44mBOl3RIMDi>Xs7XVUQe3}r& z7~hUNuF^q@634D3i047p0$)rPvv?D^A4Aus})f>ky8#R6OK6e3WArGQ|*f*FdbOFh*nP5HzvKtxqD zd*@!KQ8@rZ4OV)9I9m2ub}$6=24sV3R@*$29uf{q%sXeze;s$pURgJHD&)M#hwU4(^(738t_NQT`Gu${?s` zsMEJG(`Ok~aO56jNg&gJ+FWxRQW3;2Xz1knf@5zNCyyGgG^U2A6HjLcy*%xU9arXU zlGMq1Q;*JwH;pjT5%2;EjpT)~z*37k91J|5h=2}5(em;#T6<6V-s?2BgO2YLW1r#d z3m7!}>t1!FhTKeU-MyYe9R3 zMJ=4v?Fa26A+7r9u`$OO`%gn46@#u8Fr~YTDu62rbgvhLaT{PoHfR3;ic-EkfRJ|9 zPfNyie%Qh7Wu{p_>0~F%!OSP0IgUss*OZW9Z{G(RxYYT(4d40~LWI2VCFxD~*pYxa zbz?1f&0XL?38-mxUZdNXetlg+4MkvLmyvp3O{=Vo@C^i-$d23}qY@7MpgI$T!krswq_8*8|3<*pL%#>j=TwrHn{pZAs=q>M_}p9>6=I6gC(}4 z@^EV_9A=*_!Tco7i||hG_>OQi zH5+<%T2)}2^f2&EEh+7d>gT7cxCx5j^`Fo2^d){-{&1(KaICf+fE4~v-xV9b_5`Rq z^#)qcyX=elwu8D#t-3ovAd1BIK)lVzkp~$(hL(VmC-PH(EF@eBk%W8RN0Z7X> zJy6v_mwOlYGda0k*%ld)U3Hxyv{i>55rqrWZS&`Dq=2b9DeZ>dP?C?AY7?+2l{OEB z9VSk5%N;nD+U-&eD2H$6fpRKGJ4E=WWeMZt!f4q5_;@Ww*SoHCud4JRZsNhlB)8f~ z0ix44lLj|*+E50ALAWG5vQT{~74RTQN8yWB9(GC?Pg;N|gWEC!~c#+j3$V1upG`FAkmY{Qae%*9d;|l1w)*`$yNGYAk zxA_pkd5{Wyc`6~Cd_b9uS2TfK{rJhLG2gS~4x!h5EFwm654f!$VZ>km@_BU|3q0PB z0l}AHI~|=DL?5N*IRg1Z#VQ8`;cHE%#F1#)5!f5*T-_*zv9Ri?^Acz5u6A`4wwe zvULL7#TS)Ye^0k4qtW9w<-5b3j`<+_w5(YOKJa&P8_DpIJY(V@{Qau?o_nX}+RX~) z!yWUv1{J0HtIL>2Vls+Z6%J#cJX4OX{g~W#+bI3aDk9??A{kkR=UYd^a#qKRLopJ5 z6@q;cJLELOXz9AfJ7Ql6(x8~?)V5d--AI--(H!bH5XJMHSMl7Y2G&X2ARE8Ck4@k7 z-<`ATdw@?##7J_zE-E0HJXf=r@Bk_KN}w?5v-GI}m%h`=wUxsG@sOL3GFm)IXe*mG z#nI}GCJ)M;7OE7!C&)J~GcZVJ^4`sI{7z9Ed!4hMPa*N8{HG=^4|s4Kkdq?mBo>gu?IVx?&v;_saST#6|$GjN3m?pR7GRjn9GGK#16`9+*M?G@0V- z4Vej_k8wJ07zQIlwl}9C9Z8KJH>cc4QpDG80xt;r)e&)Ay4q}@tLI_RuKw3oxbgw# zpOY&_fY({;iEPOoSm?#M>p0H&QIKwBP#^N{YA53TJX5>*<~v^>Vq_Ce^d0rCy}T z`vT)K+_xj_(5K&C>{0=Gs!&|umUo*ru7ACcr!<84#rrD~vWJ~>a&x9EGWuU#*^dv( zB<7zf!mGcz&SS6sm4C9-jiXz=zfV)3det~He^P?p@Ziz&Us@iLs_HLWLXH!3N$*9H z1NXbUa4enXU{n0B6^G`Nm93q39OEJ<7&Py6RR|+Xh>f!xfl5a+73KX=S1;2}8;e3i ze$c(G;glU>!U(Ca*YADCsLpyW-7xp1AT%8A+kG|L%7=#Tv@6}XGdOz#k+uJhY+K8g zW^s5nstaecXxAoET!E*+Ws)ZCeqV9X6-GH{gWx;e)N7kme0Fcm?S_(!LnGAco^XkM z>+7j~WGKbG212|CzffZzY{3r%zA8 zVt)JAJ1tsA#i;2f!jFg8>;f}g8b5^;ktVwF-<;t=$L7DM!VCR2(KG8q!ggfe7e;W5 z<~DQJCKm>y9`Gfuhw?J*Fq*u-f(fI${rdc->;2Q4K7+o(m?Yp7*s2s~kYHSDNvND8 zqJXIPKc!{Y%&MSZe*3dTf0tE0j*lId)))YwPUhj)OUK`!QO@&2YLcymhE;cwC9>VZv{OZ=K;YTm;-}CX&HDNbq<5o)a?Ng(OHagMrp;Qrg%Ipt?=n}_qqUjuX zJPmI)08}@&MCGWY1*)bLKw0Idvy`as+K@_qT2z29%WM+sL%JWj{dgDx*7~2Cts}ZP z_n@*rM^{&?KyQ>Kf2?paq;jKnmBgt%Z2iSVwp^e8YBLz`T`q|y(;IYkk0)Wb_U!$M!$d!>&X4J-la- z=;XWf2FR&u0`#!7GN8hmlLXJ^a@O@D`5jm{3QK)kO$)>fC+@g1zv;S*n^fi49*7g{ z3QR-FRE)*eFSFFyApQlkzdrs8$Kr7q>7$2T5=(0q`{ouK6Cd;%%qtF7Z95sAr+xxi z)T)C$+XN)1gvFB4Ra&vf)Kw0X*!!!;-qK}-+`-;A9+;@wkZrBJ=CM-zs68V`&Q1^* zLf}Ej_^v=Jk8?0n^)(2=ZQj~7qLVs8C*If{Xz*Ypko8x^pngP9{X}{8y+IoKrD!SF z>q1^f*NI3sb82rqvrIAaj+F4nKAfow^hTrRCO!u*x#DR+EcACPtqmB7W6VnCuQpQu zl!K7T3?eO7+;njxQE8G-u;5OkH$VHQo^-@=vfRl%v63TuewIb7V{t0+BAbf9z)D13 zkBBjz&mrisT>%+m1nXV?N*vHb?{=MXLm@fplyyN|LUUh4ZsJg#p<3EK?v#{m4LZ(> zTsw{%+Xs_3=gI?Bq~EC)zA)UM*KFWPq`q=T+VXi?kYX||DY4;XsLF$2ur~P$hfHOhpg#v&!1nNxIogB9yK!+-q*Mlj8B-8!Cb zCDm03u3&gn&<>8()EkD-OE0E3KY8T7?8;HbYuyn*a%*(C4v4JHcVg_kP7X_`bULxB zuQ5Jts;e&BYY_YVsZNy3v>_^zuegCNoJpqu*}Hd4a_d=H_H3;*lP2yfx$xT$qn7x; zwF`)PURQ{Cn3uxfR((AkUQV7)qe4g6mRaz;<#>6ZK8c-~ZnpiH|EY_2}p8-?ptMLT;-gJ+8AIP{4(E^zJ<#t%rF2x|Q^Vnoap5 zu3_=3N)x#ck8T^wh21Vh-4N42oi}jZ(t3Mrt(^9bS>bxph-^oqkb)bplT5a9Y6#FK zcQun&+H$7O`ym*{3Hq?8{tKTZ$!z4y$Wy_k{fQAJMZVV* znf;Y>ySn1x&mOI7EkRj})!&s?oo4Fr7DnnR6{cMxKg&qR+>4A9RC8YJj@Nxh^Efad zN4)B${Jju9`7K54JCD=7Lp^_%dJrV?73KJE^Luu#?oxAQxYJ0!J_+=jBSygWH=#_B}i2zIX2Zc&*XW zCTkIxYgW~$K6>wC6l%ah=u2~2)z?!XlrN}}gx2@|gC8;_PUEz8zEFO)|Bm=2>IB&1 z0bJYa0S=hmecJeiAQFY|u1-p=?yVQiw~Ct-aP~tm=tI+e-1cwoD21OY<-MWfUOPRM%K?D6Qu z=5(B(j8C76(R|0)m=G7ppj2mFlt7+Zf40@Hn}bzGc06wpFWsmos5g|%>*BXi;+rp| zRPP8clPh6Ff~P@yM9wPr9)8*yb)8fyEb*n~_Zeu;sY0yiLJm6YG>j_gR7{-Lc?Ws0 z9%n$0Z*P^VBFzcRm#3S9e!kGFx^v%WOF3QFuR|~>6q^&##rt^4xbB^)tjx&n#}4{p z3vO0E$`?%U6xTZ(e3l5P^nf-A?ErQNo?|4$qi|9oIP018z$1b6x5j7A6MYGgnFTGk z2`9&$HdzN#8nEZ}F%&)$o$r&}YC%9E1)8{34gzf$&8nCgW_A zL(~)*COs(PK_F&J)247X8*s`EA37jcnl(jY&fAB6b_}T8=iihun2_3k>wxX=&IssGD+Yu-aNI* z*~bc}WcIvvYXN1S^>U`rP`QoT8C-4{t$U#SV4McZEAT*RX#dh;yR>qdyFp0^i~tN6 zeQsa*b=;re`M>@pbcC+$_jh+F>yWS4rWJwPJ5k?2ML!2N16Jz^%&RN7QbyIr2ebM5 zUaH}iuge}S(y7n3*uI|{Q07N-fe{COw-C#uVbH}fOIBZ2M5NS!^qb#G^Efnx@;FmZ z2_fdqDq4|%P$|=iMZTHcgA(}qiAGsw9Q~yE(#ESDh&`rDmH0bj_j%D_*eq3N-&stz zwI=eU7xTVM^2>Frxy+P8!Yg)cR^F`+wXsi~6Th3yQx)0T`B9;_rf&)|;3jL83 z(tNla$3rM4XXr&`mft}AR3FB3(AXSywPGLXg$CX>?KBzCEAfPqgwemxWr81&)2#1a?m2M8F9F7=Y z`%x!h5etRpu@F1}w4=yDir{q0D>txm{Xx^|!@(q$oHi%)O#Pcb+A-!>F8Ii146 z5wM~MP14U+nZ(Uh;V@WY8VshEoKXf=c67k~+;uRZ!2<|Sfw~?FrK?4M(b?Bcy0^}5 z#-Z9>2~1m3#qAB;B%LT567t>Bh>~op(%n!%{}C2HSfSJdyYs~J?UAyE1hXBx*`EEW zCi*x!RU?woxOlP+kxNsUYx$FU0d8BpKUvV{sw~Ye-b&U<_=- zW}F(T548Ad!&s-6kGW~?#&(3hfmpyX7&x z^Yp+^CTK5kczta^pPAZcZ7`&&)#Qo4l&pTaO|odN?$cexd&ZAATjpjmQLK&!qA{JX z4&hqh_ss%P*r8t>um=J`X?GQuwOo7kDoR3gh*q^3M!n&D)Q+W4H5?pzRoU*g8Q3+% zIHV3`AV2NT)@XKD=nds{hLMV*@}@OEFLUgL0b0L9i6>34bXVWGE7jOjB9n?~#k~{Y zNVGp19d@m@w;u_TCnf_{hqqsAr;9_`&P2(K^X6;1r3RnmUKzrg8_iem?JLz8aF{0F zTd0oeKHtEyPCrFVc)NKyv)n|`42LmP*(ncD9EjQ*Ld%+E2m6%!b(Z*8C?tG`>y%Pl zvI_eg4(R7Ok^&bby``h8p3iIu$)gBVm?!uK@w59g)uSBnt<4GozRtwyhAvk_r=Z`u zO&#trp@L4~#6C63I>oCo2*dIrT<(@^e#fx>zE_-}d?8C?=1lWpY>e@JcUqIPUv1I7 zd(Cj(GWZ7LO_OYC0cH;z5~_shiWv;{)?u@sP_*0g$q*=*;qU>I>UXoo0f&;laYT3= ziw}{T9S`pa3!$YDv8Je7Pu~4Vv;QknwBAGgiWHM*Febb@N)bm?xutoRT;4sv=xA>i z&MFvSP|5MQj8yc=K|5XA-{06Jv)N&{JUGj^xHUK*U<-(C(tyVkGQRDyH^_{71V&5s z$W5rFdiwH5q{w{JV7)BAxwfEuJG`vxYUqYp{<<7h0G&n-m0aS^crrfl zPN(Z`h-z3wt@-Y-RKK?Z4IKL%tiG?wZFhoFO)5N%PP5K?Z`yq2&JWf;l_Shu4M||B z*-jjKzYxLC_5S8f<0>g*{i_mo2UEd(xr+eA_iiVcPTy7q)#@Fg6-(3=A;mPOmI(}W zLjn)()R6>&d6<+3Dz171S1LIh3&^zlPxNquXD zET4Z}hm*#vkL!LzS&*tcxobB;zZJcU>QAE7Xvy3jQ1hTqpCOFIEjm-<0Gr`Tnwoddkh;qkl;=}Cjo@OKTXXN0=9JutegM^DB`^S2 zbblrq^4NSl>85U|>lL~O`t@p$dM6ktH^8fx*&hforEs~aeBWMrXOa4FzD@~v5no;& zF0ufwl>)zNv&1ALVo=MP^+p*NmeG9N8~fCcp*LOf51#!W4;CRfdyi()-w0q{Pbz9^ zFWm`ZvKlu^t7|$OEd(Al!!D2s7r=96fWL?$7}c@Ke+n+g&yX1e^t&e3m2>QY-TWDx z&9VL!y>zwdyC;7q#niNBzM{}H-GLp)+f*hpvE=-w-Cjpd7hAqI?;{D`!k-L_R(Kkj z9U!%9Vn>05+q=S4ORdHgD#Sq6#{x8VwZ2Fa`G!TJ^2S*2+<6Z7XJ-+0oz+w4v0C{A?LiAQ8HH@#QGJD<dQ{qa_svHhm%;nz?Gt3Z= z!oIA1tt#IlAZ-L_pqQcl7zU)~`(2au_fgnkXBd_F7*ZK$AFnZUB@BxTng0?iUL^dy zYfz_c)6w{XA?vh(KV|@iPQaV3di1=Y<$-S%p0<)_f_uf3dwAsvX zT_h3LpNFwThqXqUiNo~)m)rj6^Io!ycfTXEcYi;^A@QQeh7dvhsf#<(iOvb!t5;VT zx8g72)GsxQ-7)eW>9^3U2C73s0=i~iRx1V398kT`^)I++VAK0Bf0VCYC=8Y=3hX74 z>a26(PkYI~eh~?`sxyCY2*E4<2>;Ju0)s}SyH&iXU@)Dp{G8t(uCi~w%mzb%gVMXF z)prF^0AhOP+3bC@caPU|H>ny4Gmil1@Vd9i0_fB#;7o=R71;BmZb)*xdciSEj^DSV zW zNIdq#1ry37+8-{+H$7gCn`7QbV6)=N7by4>52p@sSV7bfj*Z@H^)8i8PMTceH!)ac ztX__H)*oa--6Fn$n2t>3~+Rbt<9=O&%nO6ZgRQAKi#CysbIEHc~MepW$XI= z6Er5bHkI{;9F75b*p$<$AUIxmTQmQyLZ0j`2GerjfM%(H3)9CAGQBg-=f6mPaDkPX z6HVzN=S9zaea#M)d>*nK|NborwM{UCYLgCbyXhllE5drId_6rE@-r=AWf+=>Q`3g zONZ?0!Kvj?zoCDAnx~VEt+GOaFSIq7;@=}Wv8ySP%IM?KX|Mm_q+C;Yw>_#0_|s$z z%2-9!E3M+v*%}x3yezV91Re%(jEx$&?uh2mDm4`S-=)1alV+#u$51p1H`M3CCm=!|egd z>K{@LPY;r1{LA}8oq(bdhT7gVcAJT1x(;VokFc{yKH+wjSNH2B-NzjWWywQ)jSJag zu~S1GYSVNnBl+^MixNvG)#l^yXPehX=&3lEJE-qCxh)b1%bD^R>4b4iIK_W_V-;j3)NR9SHTtTQWyVdGW*& zIn*(fVNjBTU_-gq*F8@DBK)@UaG;PxXt7WmXvZRh&Nt`1oI7*#I4s@MoMh$LzDjwWC<@=gkV!I33@hKRj{cOk< z%f;DjZ}R=kn8zOwfiWa_O9T3eA)vs{Hfi}Z)7t1}slXVJyp{bgorY=w|FS#X)uA6x zrA13;aSG1y^;TLEf1ySNJ|3Gr%Xm0wvOr!ae#q=(CpT>ljoa;pJ(1bMXRTXuE*1;x zRQYTBHB;;{eNpV)+^{Je2~Xq zw%(-5IzW<)4M88OthabN>AlAb9XK0;x2`;UWxOOnKCR13*?Jgw(Rz3eqC+=logF!F zZpttbT!e5N{6Rhm^s&;yD}X+g*zFE{X6Xw#*Zn$5MaQ(ogHUG~ap~Tj^4+N{U1-6H z#M{U35!|H;W&@V!OL=J)MVo^YoiEQG;ErlfBB|`vIKxMCMh7TAd9)s7t%Udpf4l8D z0-un{9q!Ae&22Qy_%cE z@#X<{4$nlsP3+ZL33pT$|N8^Ha{D0;O!>t}lpM2p1mzZNH$__h)lbX1nwQOih=;K1 z*@u-uO4e6@8NB%r%!tLf*T^PIuC){8^J%dZOEh;_Z&E%$(B_rZEjmdA8cu)v;Pf{`bBl>UECkA|0`llY%s5jo`gX$XeH#L=osS0%39n*>cf)Hga=6C0IhiR>MO@%a@ktHXL- zA_+iT&O9p$B#xRs)enhc%1x66^vvBsAo3T#Rpkq%@Q?8p~<}V!))! z3GoqCo{|U*==S?gz$@Ku)i6U6f#i6>d&wxq7Y|Nn2r8APW~e(RfB=2^z-^akYrn*L zw9p(rrr$R|__!VQJP?CEb#mq-lsT{7A;)#>TA_`?n(fX45}-s?_Q9I+!Lu(_Ix$t7 z&4&Y)wV9wQv)jFq=Au)zy}9(IYO@4*j%N-|=Fo*3r~(jin0wKlNr;H_!afiYr6{U^ zRStcz-oEmbP}`_H5F|_~DH4~8m#xOZUk#K3nyFPR?Gx!+EH$>RQ!>4B>oS#9`$+Bp zzwxmyV@~N5Yj?_mY7$Wm$d>yrC$O5J#}VBgGB}`Z55_ctF@I)!Tzp_a+g!m5T<#<$ zhfSifyyL4A6gWIC>?9ToCJ%>q33sUjpNLXUuM|5(LoF(!3mmr+80~Tr;7prHUkY0kh6j?qnCm!{gnvNjs+vw2sZwEJ2^E zHZq?q$j-CxuC@zA+jCJr+((3T4yNweOQ#4A^oy1)|T&5O!G1R5;h%-MP&WFEIEp(yEcgIoqz$=`mtEKYG#)(%4#h)4?`H` zd>c^6g#AwSBgyPU)#`1r`27JpO>8`U3S?b3jgM;yD%Gk3D93T*aH8zxSne&-w+;_4 zKvU2jUERPeXpScdl(LzTy2YrEyMHACq*)K(5XI_24<-uR;rRyrUWu&M)T26l$qjC> zi}CbhIwF({<5etU&YjceYS*Wi+>eCLvfR%$HsKc|0ZU1PK?8j<|H-%KcFi#?)KZu) zWSrK9jwE9py3H_a?4s##R5mbP_naM`J#Prd)ms1rW0Jk?OXTS&hu%x9+mVg;6b!X# z_;&7V=oAl`P2}^^Nz<9P<%0D?lxgXK7>no2(c~5y!b6YX8`TRh)AiiWSDk?ZGDOLb zy=;|Z8B_O*w?uZywF<8r8>&01gb_xw1+Z+X%pXIwILpp zW*2z(n5tj2vuluu8E@BUcN+z?$*lmO1Rmpm4oZZTV39kV?;;z<`AW7vLxD=v>Vj#M zJ<6G61i~R7*3>$pov`=kxTH*$REZ2Kxt>XJ{q) zfNanev_@WPIf~qHqK9j7^m^uE`IdX$DgoXd?C^8}c_u*`5lcy@P!h~sh^J9-smVrC z6^+}SqluD+5M{afUJ)8}#Jj*Q9EyolHrY`?Oq6BDecCT9aTkFsC~@~VR{d6BtUUc_ zvOsapCq8>R7!fNp<>L=5=o$%*&*>ZrY20Dk4t`R^G37g@w{dxBcHW(I*Jd7g%x7X6 z&i^}KTv-Aan2=AGd3n!rvHmU-NzpCxFl}bUo|)HaDDu^Y#f?St^;|W3!}o)EhwtBz z%XA+K%sT+s=^*@3c}6np=wzsd_%EYis3NKtipXA8~){t=LC zs;RJFS>uw4r<%uZ(MYdsHDWS3=T+!5+mp~H<)5v`GaB>czrw-M&5F^kfs^NKvzu4{K)=R`?h9!aFm$_&>Ery?LC9* zn#!VNHqGp-Yzh7f$)LuovnpiW>aiuFz0JM=q)B6y*xPu-lH@u!XW*QS`R$y|#q@1< z$&s-k8JYxkCs8#;9bqJnE=BMDH8;p_Hg+@VNFSbYeBCWCjN4WEaTDaj) zj*xKu7e`3^!=UBfvuKn)ZKDMqwfdLg*gEC*;{4HPE>-H=iyc3qFzipWq@rfVH!1`9RQD4oXo4-l1ryt4xS@^&JI5P z;rQm<#1U{kkPMoLK!YA{_UOL`CAH#q2ky@|z`l!CAz1w-elX;3?*Xn8H#bS5$6>$1 zn-F}?`jofhqnFvEJqbWl;P4`mSgLI4!A6MnXLdl5)b>JllJat3Afc>pLR@+wa=@W9 zNV;FDNCoX+P!|3+^_2~}Mx$d8w?^{>K9Oeg-ShLk=}8^oer8VRi!NX2sY|bzfWu>k zxxG|vag1Tj7EgkRrH|+LP)FL=#MMm zn>KelzQ24`=J<`qEiYCd?*yC8Wytk_bz+R#_+npqB#&2JZ^-n1>}z?^S9-NtUn`WH zm6=f#1&#OPfMK-k7DIE-MqQu zz8C@bvugW&b5hIKY|4NN%a->*(Ck=T@s)c0u8X#cVl0n%`kAOH8&8n9DjJnPmwu5X zb9EucM6ILpz?2<=b#7n|ry$#|;o+ewV%y4WloKAB?r>c<#i|XII80~visruN3cD$) zSVHj(!HAT$kq1w8Su!|B!e1|W$?#c5n1ycaV}JDSSxJ7c z1O>8Ks`vZ8!!(~>Af3r}^ZoD(yySyud{A_z@ubO&lR4_i`lk5a!Q8yT+eFoJy?13U z)Ap`6UzWf1fp*Qtt9??oWOk^tz@r#95z5wP6GO1Zb3Z$t=ombFkw_uvK008efb zH@$(Fm(wMhEcG@3Z@WpNlgFQj_ri(;jow|S0d$Qu+N`d6?smzt+8tpL$6l`q3IClJ zs4TNfak)Gs4)f`d)K48pi%w>BZ>O~zrcr4`1zA_U>3mys-zzG6GIccnspE0JHUybU8gqR?mKWulh>2obD=k1-JNOebFLJpKAb?Bb2#~e zkGAkmYx)T`BdY9aP!ki_x25_R5xVh%pK{+j2`iP zBbWO%81x+T_ztX(5RpO*g@LlA&=dtil)Mlw|GAnKL!L8CZYl^bj8dn)k2t&o(1mfg z(>kPM5r@xgZ~1W%Aql-0Ks>y9m|k0@|4PU{U9WV3FX;2PG|YV4mGS#87mE#9AY3Rd zNN=vnhPtt_u`u!cVDCB7msx*4KNv#Q>O#lUD`>#Xkj>dJI~7$~M0g75L07NTg@onp zG%^IBt&UqY@PHVe0)L~)3#3y%Hgw?vKApknZ37A8g*n^X&4|O^TSGT0lhFd9NA9Kl zD9K8~(qqhE1e&`2V;|VL6B?jEve{x@fKlV^Iu!V`~3y|EhJg&iJwkjhncv9Hp$lUR8=@IQ~_)fN78?_2>p4@LUf$u zJSy8L@WR$~8N13v(E+941H@CR<5~+2D2^eaob0@f0vdAdJaz7H>C5^0n1vkf%mcSf z{&Ekb0=YCAggD|Ceh!TypJrNBHJ@WkH461TzSf8;EmMu-fu?-E%U-&XYVM)6)qg{> z0u4?P_}y1NBka#HN38!n=2Z7Tlk;M0m=Nc1Ukk4?{>HMw6RzqQ~?M3NIa#Dy+_lc`olrvg(=p8E~K8#&%xCu4Rrki-#QRoZP*_IvZ7GYV|EJ#_G?ovNqpt0)#_eXt|L84(MP0jztl%w@&~blzDP7`Dj4Nky zAWHGMkxe3v8A}sl)$^U928g!1KY z40}^1A7TMPMr3CoDnL{hkzc?x3r`)WuEDb2>J4CbIAo)m;)a~7HY@6X0>6StOw6Vu znCuP*_A|NqISfk8re(3y(wTRFBW;&(dyFo`Y@->Q)A+3bYA>QQILAR4uV_Gd_PMP>FNNRYTnXt zlEq1aC}(F3hKL(S%^ zag;ahPP3pXWOHI90Ih$MhdHW}+n^LBq)4*{JAqNZ@(VO6Nm1BK92VsbRcG=_sw;XV zHJbzuC#rh;J?%HXj*zGT)@uWFE_w|PTu$rO^2BgPEnPr8Z%&yj{5PiVm2b2`xt@p*ESgn$k z?)KX+d|u!N`T_|7a#-O_tiTr;(pPrDRSXlwV;)!_4%|1!uX7}lv=y@@4pcB-=d}zW zgt}RC7b?}kFc}WnJ9EcSD?$JkVqtIa6T8Ro=DYjLWu-dfH$oBkAppRclSlH$V#*Re zS?#QhWT&`{RnHxOLVYIbV*ZLu_ z>pK@M!wa)<;0s;=bUQ4Csr332x-EqKhHmP3Fd%i(^KVnPK%?CgfH7RCwR)cBenANs zkRXsKni42$VT#B?c&|pP)P4UYKpXI(yb0fDj?~MFyl+ zYe~eMYP&yRvstJ-E?p_|jVFv2)YWi#_~mE|@@luBEoYz5e*;ljDp1{p9=z61{s2MeiyP*R9k%?x1ezk~_}HBdqv4X`di_U@o|= z(P|fexL$7*S@@}I-sulca)lolxq&Bg)kzDL_q48}8D8)!0rvAD^8KIAiqN0Viht_N ze{OgGd>5Y=(5EAm$gto2CL4agpDy})@wX!w@n!`QZV}8BJl-zVf6G@^IB$%lC^xRg zz42HNL@Mh0^dodjf(VyzY__hSXaGeGMvK*(^F8~`8l!QT6n4APenSXoU+^FE6;le) zC~_tC&*$@ZcJSX^v=T!B88=eD0P(+N+;V^W_pXRY15t+~P^!(k8hu=dGI~~^K>jqT z%$yK%c`z`PwgfrX&c^8)tRd%TOgI@v&U+Qb$+B@wVT!6)Pr>LmLg?~X5_ zbpqD#)%vaxhs!Nlj4=FyWx?7el-l#DpSI}Z4`4tH!fMnJGGZ90|#Ju4G{PA z?m=*IV`cv{WJAIHF6`=KAOVkhK2`kH_aMnf9Lk6t1Bst`ND(n5B)*zf2S_G8!50#F z4%p5CvkF@-Go5-p6kxEiRT%<9hB60xnzI9G|8W)|_JMyiQ`^7L5#i!K{Y)mZ+0`TBCv4dm;mYv7@(k5 zAPppXB;a!P^;m8eOs=&;xslqbHDk*o*=5qg$$N@v%tr@E^O^%o%sJ)qKCp- zyM7gz*5{S;ElhyTr{7o5M5<7?lp=RrpDCPQ7$F=JU5*WKY?FuZ z$6XuP7g0mgF{FRL_&>QY7Xc;^iyCU8z@IZnTkQA!RN)SNjf?^b@NBJSkCJ$#YrWBL zO+>@Y^Np(Z0{n5Hr+UvPK*H1dYvetrCZ;aHwZDw62n z27gM-KSJq`|Kr6#qP5Qry?6QkP)AsV-tTA-hk{Fo5O6>1zmW?k>1AlKdM^-;IZDM{ zi^6DLrv2P%_u}Q^n-@`S;-Bt+&TUt?Uk@$f+u=Gcr@!Zk&sSZzobdl;PZU6lneqF4DgNNReYu~%~s_#SX zyy=@QfpoRF4nhhm6M(BLHZvr~T2*{64P-n-;YrVb0!&xWUpI$vY_J~lzZlXLeli~3 z^?=6uWSl=E0C?E15%m@ttx|YCRoL2US5QdR9fpo~TYmv4c1)e)_Ne{Jp;*@jpY%uNOUCkboqsY078n&!6&SNBrgUC@}d5 zk{2q--x|WL5}hYA=WzGM<>IVF9Hj_BB?6nO+5xn24Iza*4L6G=sERUvyA0gWU$fOa z;YSh1c;{`MCFYC_F zxdTq{1Hc(b{4WxYU&9zd2!uId8kDeqMn7aiFDcUBm1Ex;r~;D#CNOaz)nM{qjyWZg z$;i5(v6YM>5RT^6)UQzFwL<*FZFUX(=K(S2TiKo5%X@gw`PyO$5hw!qSBmM0h_t>u z3SzNX)^V6#3Oo_dLU1TYXWFYV#xmHS4GQmkpU#__Mk|W>gT}ff2R^`U2@>tUeSi_N z-yh%__yB(|rh|$grlK+4cL4A}H8%aN=C$$vK$*(_8D%c`wpz5P3!QvK8~s@muqa-b zf%P;Yj=v#eR+^)^D$olrs$DZ=s0<=FWH2+ayKJGCUmWJY_zZCW{J!+frC-`eo+4Q- zJ%9@q9n3yp{TbJM(S9S(dUznW4|$2>2>`QCi<=@J;r8b2na6pRr6<`SXVj+pXeeK7p8dHy|P|NTN+Y~^cEv{JR}8{j+&Z@@^g zR!{;0xOlamR9aY|bzB&QG>Ehr*n7Lc&;haGMG@uf$rP6zK84a-rT_w#413GcSj=BuDh{Yw*?T_7Lsmmj4# zT_j>e;@gZc+O4;5CTFtd7MyOtUyNr7_InFPawwQKFqbUfg`wLRtX%I+KPjz@q?JqC zQVw$hG_0;Xu)KnZ*eXx$DU@;_G(E1cU4}TPI=TR^NMn>ZL!j#uMI09y$w6`3_<@6B zab*ZN7(algTSs)%{|q8mZ~rcfkOxXg6LL)07aZ?;_N!&fWVY2ZLKEPPeS!ZOb$eFQ zQffDkzt8T7ih$42euhDhNNTM|A{hro`H_@2aiSNAWeCA*FQ$qc3hYt#2;&AG(~sq` zk+)Q5%!lItb3Wt`4iGbbKwA{{Du4md)tQ^H5{Y5(Qcoe5Ow9;m^SWF~C$`uB z7{#b>EtbRxFP$l5rPOS20P)nSSUW-Q=KG$Pwf=inS_g&WyK9@*#$zx*mj_!VeNRdH z7)sf8;75v8TcFM6?W~ki0kb}En9|%%GA^?Y831b|p#r6j1L9t)o3jJ@wp`!G#r$R{ z7>|V4=s2#DN*g%PNJ2w}%cv)r-3;Z0#Ss(!;d8Rxy3^Mc3fDrQB1P9i(^>e@=7+8x z>uWZHeh6FjdZ~Gu>Ujtx329J@6|H5BO!A-IjVTk8_0l ztze%a{g1V=3}fR5HOla0?^-jT6!g)4;kAFu=LLRGCxvZHxorS2O^TcOg?OO}%vB>4 zat@OX!I?%Q6hCYhH8ALRxdLr9N?L3RWXe#fV(cEUDq6x8^N!m(x@&Xc#bP60zvFYg z)^}tnr?VBe^6PAQd4(b&F0J#Cl9{WUmfd$i@{)Pqj}lj30rg4uyj2;Qv| z;O9?OT~c0G0ce=%w`J&mhT6Z;ml6_Ux+2gNN4m=T#p@4J^ZB9B$WSz1y|M;6SAnnU zl>rl}U^wnXovSm~4B@OPrc*#uLms`$3tnGOHr}Qh;c3XMY_$ln>N&Tu@wB zIq%pgImzQPFO+B^A<`*x%$FyGTg=u!2l}dwpL`8M&Tzk15&6Wx1rTn*Ut|r9Euv*8 zRy)*KJ;ngfQ-)@({M`$~;ne9#oIH0xXUdnzcMEhn!&u8Y6`<5!59Fm#+cw0jxdTq! zz^BcL;XtyTy2=htyu6%q*}Q_5wUaM%nC$br+Gl!f>Qlbxe+x|O73fB3{0{(Uv}e&V zUSqB`7G6|8#7F8&mw1t4sC=@oBG>Nq z$z;eOL$=4GB4y{|usBiYhpz4ikP$-sVpxQr=Z8|eTC1q-)C8jTVi-6}wa33ie_%AB z!f$popPb<4%}Q=ft$(ko{wPxNO!O}-v^TNa>ZZ5~*$}&1y%rZ$M`JHgvF0>$BhIk` zNnYtD=nJhE%@HEi*y#>x@eMlXb99NhKm9d-GjrJ@8vHJn1>M z1Y3~gL`zViwBDZ{L#Jdg@A&wSZB8Fu+$Cgv5<_D_kSZy>v#ZOv{ z_Kq;?_^r5B9l%pw`c*0IAGtFwVy)8|v-x6kn4EE@eU?ZR?t~UP^c7MhLh6uaZ5AiH zAHw5{vY#{Fk>MGV-A13RQV7v}rSWDPQ~J&!&q^-ti{qdBt0`vdH(42u(|qtrgK$a&aC0EI?t@Nyqz;p``8oRtbVIpsmCxkSb^u4z{H9EH7W|d5=ipp!sjPC2R9A!?!64e?c zv)B)!?X_hck=&a2L5#p>^Cj}C7d@_BKYn)b?L;Y!7s`-Gj>{Hk1Oa!LTVxVb@)v|+ zzPbKR-jEv5^e#_HMyY;)Ht>M+2BI%i1;eMS$ZYQwV$zg8jW-k5| z=Y&e*@0#u92Y$Sn`;FAWmqH~|;bhoH`mGQgin zEY@1P9(FjPo3*`o{nMl^t$2C8 zIy{X?v;&Ci43&NKA0oRoT+J~J3N?RJW(FB*WSUDAgUDzAkH<8AvkYHPC0z(kwt6;F zcj@H`FhmM!CXlj9#K6wmtVQ%@(IGv-_h#lsH{R^|$-A-OosC3_o} zP}AI@2=vvKXg)%-lAM^>L6zh}!hr4-Mq+RIjNL^{j&?4K+2@YvhH1U@`Tvo(Jk3O& zK%|*E6Z$wBWiOA%%MyHIq3<8I#~V~V*B0yTaDanK+IE->t@gK})wy}S9p?%pvV%9C zIvRM~Isz4w3WaI~EKX?vBn6D7`Qus0t?XvTas@KdF5OmBZ7)boO=fCI4;LFO6nX&< zepe_q%*m22PFH9O)NCmozMHe{k)GEL)8j`kgM9|M@ zc%sn+x$@uxITT!U3VCr9))R$C07kU*m&3tQfuA{mTm-(BfLhtbjXAkb?6)`2rt|5^ zJo|w*U`kdkTQB%auYf)VMc`5GU(^GN-U+mvV-lPg;_q_oexFLk&P`Q$6f=(OiGVMS~VHB$k zL}pJT^M@HeH||6JDVhWZpxrK08WNCKj*wd(4w>ogED9oUe6fEn*K2$rZoi&mx1HYj zw(E)vnT~RFB^RE9hdGH8uj2B6Z}+WLSxZBj6y1OY3QV9eN>?$6{5 zk>eL5gS6n?GqHQtpAl4nj9RJ-7+ofQeMdzlaFRec zG=6>~L}20aG+1l;j(xPmL;wL77s)su2=5*u{+q^H_@{OfJ*Eg3&2IB;8Brx=E(+c8b1v{hS|@VmP<+ zy&MClKr;d%5@(KRw6X)yaNcPl_9q72E}+j5Bbbp)t~Eui?L>Sa{YL6Xtv#Tmk^WMw ztvwq!fubmJa^y>9T09da!B5L?vEZkMNv3hbG&kedOeJv|pv$AhV2hS8i7$gI{u#$`QUTHB~>PVk7FgcLZJZ`Y&=stx3 zU@={I=kzJNWxja`4qg*lG1)l3v@CfRn8_h^gE6$w>}TqB$8mJHGlyf;w0f(^DWz}Y zu*{d)+YFfIePo9t@8dPS?>tziPss3*#Ly2NpoTSD+7gh`Z=HgvFCf85Xbup1nB$^7 z$x#3>rjs{#UEu)$5slSGu`6z3G5b(LWob@}Z_G*qr4iau94je=gx#_I8 z2J+$I!p-ETrB}bt!p<~2LLDwNMUacGTo1Bn61z9PrTD~MbJ$%S=2+M0v`;uW9QDvWQ9XDpdVsWCsgE&~(vk)L+}#&g2ZY+L^m1?jy$$m!WBuOstccYhwf8Ry-?5C9uEBS30LlNqK&`X@_bG_ zOEMlp9Oniv#)Lh!qH;j+Fo9n{@VCqsoyWFJ zW65pVWL6jHB#g6$ZJ;q;R5-a@IGZRswU%M^Ov6ztlE^K)!~LOhU3WCOc&MwByY*G` zd^HLZlf`@;M$OSe2hi_jbXgVPCuAu-C8SA=(~BrD8^(LRQ%-fX2&K7!6< z)^|^Qilrggsqo4vTEQ!=6^4MMqvyy1KNy2a1Aaws;u1!{3ZbZBn9q(oUp+ikl$fFY zoI3(RC}9I)|L*$qgCx5T1OiK^d0bMtAO~eqlfJIw&R8drMl29Nz<@3>tCS|an`2QE(OYO!|}#mQ5%weP4828RZ0 zk&)=zspAG~&a64j?@$A4j1>8_UPP^4kKJ~g7TXr>0fpz`_)O2%$Y)%h*-m^Zisuuy zq#X5HdZ*!$1~@Py%V=9nIK)Ymp~pP0Msy^ zGnpqT432!}HH%N|tFVvK(YI4S2?mahIDapjiSnbc>5$J&DG(Q1$2UC1Sqo?qL7`b( zi7tnI9jEBj^+1`s+@BLmjZWxPo)y;_3M^A!WG^7~1i37mJ6HDhvFqvM97W1#L4i!} zVsLa#lpf8@KGm(PaJ^1`rA+Q%x8rAff{ZEnOe6Pb$xGqPVAuJwTZ|WAQK3r1q=}>( zHXW~4>$o}_ZBE97s-4^lxEccI>&q^a0zrLTnvDxTlugO^SW>s-?bh~o&z1?T3 zFp~m3`S|}zY<3Z*%@M;rb0G;lNkLEUa|9WL;=RFcY^WM%mi#h~xcY|iGa;O>pKo1Q zVx}HjOBnjIDw}K${Q|tXf;B$UKwES$WC2n3<-OskracV+d>>3iXH`5blP{y)s_$?Y z?mKicPZ9mk+Ot6dBpp8-$K@;5*`Jf&}q3y~f>8p5#Ud%9F z9hKpCYNV}yb$pRF81k33@6E!)DcaW2tl-L2M$mbKPfk&NBA>|o2??!zJiY8dzKB44 zlbe51>Z>9cd60Zx)`!`w;*`>X>eLEbo_pBgZ$8c+%5u#JAkHkmwQG+ipHz3U(Y8w_ z)c9ujouz9OQL*7;qCY@`JkB|NxbB5_x%MUsLstb)_i8udKNnZ&FN_nz^2w<7oY)b`hLp8jG#-Qz0LE=$Z^Ky!2bGkoVWjnvbTz=W8v0B1A$-( z5}aUx;1(>nySr;}cXti$?(XjH?(XieaCf+sz0ZHo>F$^Aj2ap6#Hw0Vv*!G4Vs%f+ zME3ZqF_u^c>*YympTUjXTG!uoS$mGKuhg3aQgeJ_P5y)S`~GYl4FHgi04>Ase+eDg z{}4J4q<}=>QHGM91kmDa@<4p9U>X;{lR_lJjfX`c_Xi~5DPwsaeX#nsA_{P^hV27V z>#s66fE%e)qYdM4YOYEL(2y&)%%A_DB&-2qa7En^Q7M$l`uyP%Le1RQTCIs%Tep*) zw_lC+OPyKUwAbx&#S+kf)cL-`DGvbGk@^;KvQ&L&bNQJJm!NND=FgXrIlRq{#Mhr! zzrR`$2fq9?98vjOH#!5PwAWwy4p%HA=lJ_la-i3~Scb<>;1ZauHo3Q{yq`3|k*bv! z0~u&eNaJzzY~k1(V3%)3n4b_prX;E7Yla`tDBYAQJla&_B}%u~*NZ;xg+0B!LJg)h z1TG2fk77p7vxOzqhYj)|X?ebm+a^GB+U`;7-M%QaI{l`Cb-xAGT_v|-Jl{XJg+{jf zt-UnOn76zZ&deB&c5Qz5pvi21A}65J7mrA5xy$}Hb0LAd>Jhk1E>Aa(_MoGWW&kt> z7`dlUDU`?~G&x>9$*5@5EY_OC5Wt2QcFSrd@2ISxIKROwC67~ z{G*my{xdLW%w7WXJ&@q>)N!@RNgjdcf9+^_yw!`mJ6K#NO)K^b!&H{sU2xR+ki_Qm zATg4Mp!o@j3!YLAwZ|iw61Rjpxt8q-XK^U=AHepEZ_{ffx$-yrtsiGUwQv1es&a!Q zV5Z%trt`1+ng0LY{S1Ud0t}fMyDjW~NzW-IpOuqsF8*|Mq5aEKn3|~3oSGrABnqA{ z;4inGuLDn@>vblmj=nb+L_80vCb8ts7#}|V{W*;a_vuf>9owihU2d4tDzj5IXGQ~x z=iYFX08BjyQ{$-QW-eD>>C||FH1cjJ`bRe&sB`g{>4kG6zS<@)gqPn!5QEDY&0@7R ztVI;VFpx+0{eq)ic3Tn#btIwo>VXvZR<-Wjm=Ujt=A82jLd>)zgc|a|XXx4lR-}!( zqs5hz_Ys<&9x>;sm*+9AVbgtyBh>&W&8j&pd%i}i^E*;e?=E&yfbytx0@5#^OY8DB zCHF~9X?U0g!f(Rv1doaXgq;`GDxD2$5RQbNVsBfE0I1-;)CrUE?2C}kVCJ|Gd+6C> zom2-6I!}e)U%*d%4^@G;|FdyfZ{xN?op}N0a!6izW;?$^_MUK5`}{i67uP(qm%_LG z`*<0p@}1e&cJl#Eda-`wi5$9iS|PGhjT{0|6spW)$bZ@w;E!xJcl7<#eH94A5h`0k zu1k;KUW6FdJ+Aa#yTyL!bBF#Xsww>ck7`P%IR8-X{j-&Iixr^jmPcaGi)NTT&j{M3 zNlbr;#(qe8pIBGv6tb@U{X!-0h343>efH14Xl@@qE0{B^)iuV(_{}~t3jx(skBwH_ z(dq`0CX6Pyi3`FOw)Xe6Rmr>kBoZZfSaj;tHTrFZr}u{*Ddj{ir24(8qkDO>-ClZA ze*oX0AfDvN0*0#KE`IQ4yCXUr78mt$-03DcHhMTihgfE}UFNl>>jZ3IF;qhQbg%+W zHh+*#nF$qjK#YIRZ}ikUJNp%GndHI7rpq+p>^Zscdxw8=V}Y3;Mk&qPsbzQ@ErPGWLQ zw)-?o-WT2jQ5xp^;QV@!u|UfA$1ax2)L`s1Q0r_J@g6-yejR90isarUoox}b5@nvk&UA{u2(JIg?B?gSA$%#ZD`0;cOA$t(xT;D|k>ypvpz z`w?`hrP1N=OLzYi%nkYg_+);8)F%0);j8C9p-dZKy?IbNNIF{ukt1hTQuvk(%tdd#(CuX7$XuI=C1-xux6HWdR1#0hE`AtYNRYdPW z*I|P#PG|?u6?o45cHi+HH8IUt>)_i2^9L}c&t7l!-`*ScxXcx~ppKkNG;;C%aWx$e zSD`n|3^z}a4aJz!dsm@kF`wrh8=6kWh@8-$ik_q6ddK~IbyCh!YxA1YaF*W$moQ@2 z?ioLtQThsRlS_E-|Mr9d=m(uWMwEh@8d*1UL|VQ12AR@<(jIjxTe(CooAnig z{VB*`|5Mi07u;Pk?3VWO)vRsb=?q}8(U3y=w({&`VN~MJ#U}JB#Eg$@hn0l-fX-*n8VK_!if~0}iogRS$;5+_NTVCq z$>xjzQ-qc=qpTtY3sDJ!&p5GTR1r_EtC#kj*w$yTOFV*1X*YC3fX6z_VsQt}JUnuZ zntrxc(bbOnys;tXCs%a&$OXg-C9|5>TR~88pXlWxsMViEj!XAn;vD?`-n&Svc~hf| z!3W8K?C_&(qp~RpS~>39FS8HoBB%^zJRcyq@gpH@cFFbbFh?@BjAwG^A)?k=9CG;r z!cBHQSo|44Z*4?`(iHyP(@$lS;R(zmy(j1AfObOm`&MOP_c@u|WPTXMT-IuF$HXIk zBM#aey#OP|qyTm(0qc%!ct%Rzh$1a==+oIoIh8@ya$o$eE2;ynVOFL!dyj6+mZonh zb#bPlp#p`Xrg8NHt>W{bVdzb-I_X&^$!K;Q>{j!8fz zf&65#yxUG5@lm$%iRfs3y;SucR-sUeXymcWAnAq03xE1oCe_OQ zZ647l{gJ&H#&F0_HF-IS*`E58O06MXqa(*7iGt@_buQ;0E;3sn8~`ABXi@~v&R{cS*uR;tw=imB|)n|C&z zMVFN-MCYs&XqYuk+cv`|tmk8+biy_DPG4}=oZns`>&)KcD((|`VwIV#v3hP)LW~B^ zKC0GUuET&Ht@^?NOga57Mn`!(w>HMB*!|0n*7^X zI;$$OoJo|9VdVmZgxyk`ttojTS3>;B;CbMG%B5`qc`OwVRdO;-=xR`r>g}nj!fIikU=pwg_J9Fb%4W`|XlKv& z`42|zeDRF1B>Y~Gh4b}pd>`QACTV!-IrQkV<~c&Rzg@aMn0_Qxo2TsVyQ)Gdw`#+_ zJ6jjO+!=^@rexnl{j40@>8*i9@0Jw1%+u)98;Z%-FO|d^0tA9k-#>lNN9!S{=6Ng$`-`SmYiKqzg$FYinbi8wKJ(tY0wt z+|?C48=m2K@&u*D!QGeMjAQJ@q)MAPR)ZsuS4KjMqeV6v)r#0}2pZ)|i?OdEhBd z)ywL^0aw7s_JCR&3MI-~tC@6we+k2364~Fw>p$qgD#84x*&PT^%OxILHoCpUh`_;B zNgUC|g?Evm!TXkE#d!wRA+6IO#`sIm(JZ1}OAF0f1>&Fn#@h?&Cv|_PPoIOinskIF z?)3L);H?isnQt~#?5pU{7$8javMo+&V!B=$rQB$Qo`$TO4vplI_40TvDx~M(0l{Fl zS{vtbdp8?grc#%oy#P(6aE29ozm!{Iwuq&`@ojo_+ zd}r&|7SJEre=XPRe77ozyqtq-?nYkP$W1WbYNn%GNr^?y!1idZ+ZBmX0@^CaW*%Si5hogmD0}-4a z9`kiO=SMQv>RmK@h#v%%KEj*{ChNLJ=Xuw&joe7dtBoug&Q=-ymK)-16VEcE8w6qt zW9>RRvixhjY)|b1#xwl5l17vAteT)1@RoPA9;(>}7xKr9W2eV`LWw1Zk!;otv5BGk zX?m&*PQGYmq@v$j6(zzzrp&>YGk0CJ`X|eZwaJr?HjnRLAiBZ9pb2`q6?$2K>+!!F z+!tT1;$dFLrxApXSjhu-pJ3sSqz=y3ri#O{$iA*&-rK*G#v^*+Kogkvs5a~1l&ROK z7(i1iF#_dS6n#9MyW{n)L;z}0p-Mu?5p$xO6YXIMR`f()>cp_5^zEfIh#CjUmC<-k zqM6U;c?3;zY7{=y90aMdBlHF3%s(DnLKl7J8P#=qats#RaYXA?W)^0{WQ?RmyzKGbn(N5_|^{6MI3GrjbIX6yN^g z%H0>#lCu(~<}lsrPod}FsS{U%0$NLJPW386pTVki`oqbnm})%APX;oT zb(xN(X3K@Y6w0MV4OW^~lvstYyz5NMK`un<(oJ00vhV5L;tWTF?pYn2f;@Uw>l>>b zNxYxG9fwf+Mkr_pD86xQO4nL(f>z&-&jW^i%@2{R>a0TuAbD~Lys4lYp}}5r9nY=` zqxcGK@+$5Qp6qsZUC}m~52CE%p92 zp~BD#YmklWeczuQ+Q~JF9=Y}tzUO>323A#6H_wo`lSM!51n^ni6xbFx%+^cTj&W+x z{4iQ;#>6DaC3ggKP@-ccsMO8`=D%vozF^e+OWgp|>^MiAy>r1ZH8E>QHskSh7M1-S zJj!^Zwfq`(i^)v*rdv=k3)5PgYlLe38GnPtTKrL$y@a0r1K8h}`R_=t9G}63ZG={J z=U^iUv!-#3;~nq>>eN^oj^YI~Zgd*WdC+3*Z^+lTmb_>FI1~G^ROfh_G#dZg;>}@& z<3g?X?;vT5Ca#eLs>~eT$b5CErKX>@`JW9Qtq^~LKUu@W;Uzqb&Z*}u@)T7J;Fom+ zJ3?jrVfFWD;nddrTA*pHv|E*c9aF-LrcBX~p!p(^S9Vv^9c%{>XtAjP1>pkXwT^dk zm?n?;kmO;ZLMdc*t=V+K6IZS>q@nDfgOO(!s5mkJ=ac6Z(@EUGR5qp$m)g%CCVCSKg*-nk>>@N6x{-^$ z%!Y@S*uH2mn3q&cTANfwewgRFKpM7}&zh}9@O?qZD~Uh+ZGluG#*m2&t_U}#%w8vQ z>#dh0*~5bHs=6PU5K$Iw%`!CxU-k&Tak$*X!4buhYQ{S8AP9Yo2*6@6Bik^A5DXnY zw`UEqMhXyF&nc2G+J5^rb{5Ybzi)NX2_K9)(hLNW|LlU3z|atI#_sXi`11u6T@Y~V zk8|URe(}I2wjcU-2Zsrqt4{=X8X2-t$p)t9+V@+k_U8wg;A`dDhU0FQU=p-ivUuu` z3ghV^+0Y4npWR&tPa;Sr@}aff-lh{8>LzqX=yC$4kJOls?i();Z#JXqt5thR4yOfK z$?qyuV_f3twV)&DDbU5s6CfjG2m~2Qd^HHgLh4l#Rfy%#bP9$t{W@U@49`{sI1;F{ z{ibv$FTFLlQ`hCXvR-qI0UcTs7O0m^U_jDJ(auayHnPFKH3DmA{cWP;z97He1M3`a)+Gc{9jAt z2WV!z|3Cycu#o(SEcW*fpcYb**m)%+Q`@xsn78n{LMhe8EMy03U`QAN*8b7_>PQelQKELhP&r{L|`8aFg zEe4io#=z5&3)PSAZq18iguY4>Z<_3&`NR1L3xKO3S|NcyiJaG&D&%zewl^~s$|cg; zQio;y6u<>3Z7TV|t5Fzc?lXwZ+k9s zhno2jfwQszCw5&y!DyQf$jGDv!Z{9m1`v4lHU(L1^_~j}J)dKi@sW8s^E${>-9jv0Ea?VsL5<<#K-Us`n9o_wF(33uc_| zGVZJPzZs$7Iu4mSnlUW$=-H0gbN9U{fzJV6A>e`|2KJsvL!6&omX7BF~D!8M>n1rBF&_IH_ z;UJuBFpAQv=JL?(XmK{s97i)ie=um{>K)nyW)B2K79)azD{5HItB80J0n>MJx|T6i;|?5&U(R|T(oG)%t7^5gFggP7xlTllsjxX5c&RV?j9nefZ65B&RW$-X z0%JRdH+_SpEK-Gc_2kLEd67f98(2xF=-HT|lvu#vVpPuLEp1HcZY5sb%i?bn#svnJ zovq#^lq2*3G_paiUb$e*6%-1Aoa0}$M*J|u93``v>w6M#AWVAa^F`iQMVf*QzryP? zzay0K3;4Cfjdg1v%})uBBNO{og2LYNXet0UUs6mIUxiXb@XB~4Dm~EuOU)g9S-hLY zB8DgyMZF4BIhP0jQhRO*>nI(>l~-Q~s%>wcOxW~FS(oXU!uI?7gPX>OX;m->Bk@I- zf~3J|)%ML`+uHZ=`unoybEA$(1PJvwpfr}d>`hw!H*We5evSyu0zOWcwW0E~MSA1~ zP2g-@7mCYqIJeTEdMl#SPvCJLi1-3=Q|^0$F-UF0^Cdj+`bN?n%-HhKOH;=~)}(BZ zt;%V`V`4#=L`=Xu~I77#`W+4sNFSQDJV@|GTzE8Y>8Yai0P2v`PG$TY= z*qCP4a#>~+%#~);mmqp#HAq!aC@~-&h#xPnqv}fg)Y+Bh4K$J4%T4tCvbBY?BQ;Y0 z$pVlui^pc|PLX`K*33Wtw<9b9Izra4Wm6x`6dcAMx#Cgsfg}=75nY!%nvL|vNq9}K@c>-t)MP5-U;`3;8 z{$R$G;X(;{CNr7~11DW#arjLp=3|*e;mw)K)5BC73Q@3e zWFCLm>vIz_8@~!1CBHTg&_^Pne41b8{)Yqdg9LvvM9PSu;>q1;f|GBN)IE(YbKfuF zZ;SalP&8o`@<78Yq96%)gboFPbpp}>dJ=Z|L>^1OyZBF=C2~I!-JAPcmB8R}wxTR> zI9*6{cH}HS>aHo{g-iS$dWp>DYK$pT>lVL6rQt%sALdA9Ki}g?1DK+Iss|VpBiP1a zdKpb=`t1|@@b6f3S0m~75@sc>a_z==0AA0}=YclcmSU$)QGfE2FG)`=!Y?-vr!2?a}G- zk4#QS^M?{QHKvNJ-JzIbz9#(x9S@5tAcJN^9aIZ z-zv`a<+oYmnmu~aygZQ@QE0XlnQT9p!%;jBgR`jA0-<}!*OC7aI=7B^AbWi-KUk@V9-U*Y6`7Fl$AwGUw*78hA;MCnV9Jwzedt> zbx0M-H`Tl0=^Up`0m~kW_{n0vrFfL~*`F>}rLa0O!Z-q(ABYrt#4XHx0CB1)g<^S} zCzIJqH8nT5Ovo@I(6uAtgVzy9Fw!{@_M-?p4;kmpY5yp)tCXpM|wLjhdp(iQYvWtnl>gvV3Ii^86xf3CB z(5m(_IN#v&_Y1VTPMA=RyF2QbK*`atb!HYQwOTLqdL&>V-w4(fD%@K=y1JOkRYAEt z$WV~=Y5+s!x4{z&$0k^#Ws4&h>M==PbzY%Lln6n1o}MM9D%whjTZ$_oVdJls%jK+G zAt|ucmMNHmk;`Dhf7TDciCb!L-mOy`1puA%JVSYlMcQRhQ~+#Vh;hUCrm)@L`gQyN zT)&#ex4tb*2aX+&6+2c)`#;GS8=wXFW+FE_Jr?g%CeTPZfab>D{l#8Q=a8(|uN1y9 zG6}qcW(w|)=Avx&1_^S~VPldt-23WDdBNG=W%aTl+&%5X92{g&Y`nLaR*`N~et0NlYm3kTX zI$zA(9mkGx2BZoI2P7}4kNz!S1wa7<*{fO4fAD{}+@6euA#U?;DL{X9KFz1>u(=H7 zcHh83;n{6y?f4$}dD8r9jJ{>LQ2@*bUpA@}4MN?|%VWBQ@w*r67owMM943WU1*C@i z!M)pG)p#UIQ|V1%QAxFvGczHg+Fb4P0JVt*@rvDvHU#4J#AbX;yWFG#|tBmEru+C}@f757604~HcFM({)S|Q5h&TU~+ z?+hv^gpdol@En<$RQL@T1R@45*f;E_VuY<$kdlluXt%K$$Ps zO0>hNRGEE$y$WeU3^-qcPjeac=XAnmb=}ufh%Mh}EMiHK!r+P?jwdV1E5d2ta8@7v z{W$$NeI$qL_IL>_Zwba?EcQ3O3r009eCM7?U@7r0arpE3s8+|V!};zTZ^=SwLU=-e zn`2VkL6vG$_FnEs<`APt4M||}ckPwS!UN|SN1@2hlPZ=2&`oXRYx^Z zt;me2=id+Bsp|j6g}Y%cJy}c})}xd7BdzZM^IgyWl8G*$hEGWDYSCIgdbK{0K1~sq zix(4_D4*l(BdJfKa3;cg&_t|@Tw9QUI}x2;c3qk)DCYExhRr2Vbs~lAdi6g2y9Vwp zWTU1-g+=p2z$5)V*Q^B9nm@Hccfli>b48C}Cewm(IE}tUaeZC# zM47hk{6(HEHRD-RG7ynIUy2Vf=;tfb=8T-bIh=9`1470~g-?Qrj~7$OCL4Jblo=eR zf+o|I@vHaeLco?Fvf_txEvK6Yvby6{A%l@rTAVL8Cl)o(p6@C-nx;v(9IEok^sgnR z#X7%HL_rkK*Pt&p=S=E?Rmh}lJ|JJhZl?A##^aRHh{S*bSM)Miwd}sl#`${CJeH%C zA>gF7JL$ztavi();!LD0zFA?PRU{th7q77WLdcfBP7J&jb;LmM~sK@PBlEuiZ_^zm&kG zB?X78eqZmK&*mfq^cb=@-25z-&MFxE0;zyIbppq#{8Yo$$_E)=&BEKk>X&Mp-Lc@MEHOGhlJ6Hj@ zE^uS?ySbgAkK;5rE%or$1AEU*jTVoDgZAcXWQnLX*b}Pt=`$jSj0LxH8PPcvpe!f; z0nSp;5I2LCfQ3mpz;-sZz-4C3qiG_eZ9kdTkj)Q3Z6sxeh;oU_{Wvya4Iklnv-jY! z{XDEH9WD^g%3s}>Wi2-&M(gfQNjwxy6r=9tv-3T0cBbo}%H~H6h6aX4t*ZD|mheMF z$D9XZj^b5^k378Le7y~QyaTt^c0tpffhv*7_iA^@7!5trH!P*zB)nUFe65U)(R>;o zUtw{q1L+_iEv;FK;;you@5dwWb5$jAQBK?u~-Zx zFg2)Octh3#?~7PCMysbyo^<(^_(xFdQxz>6H`-uE0-fPFX-Df)lPSWNYb>gPn$-qC zz>^f#f=;a}s@XFjEJN7wZL7Vw6OIjqT2(N9k9G_o-ANmi#X&R_>Z zOZ;q8%$`a8zks3mwuHyQY_+p)Ffz%nG)~)im)omY9TAJ;#i%ykNK6675GrUdZfN8} zTH{ib_g7q|bd>SO1Nfme=er5h;oYg2Hzc@GqEK94m$(Y?xavLpbnMExa|BSWQTYku z02MH2Z-2fy^M91f%QEl}mW`@CB8yM#y*%iFVz8NUQFR41QZiNjrZ*v<#`%Jv*_z2< zkq-k#X`m;Q!}$PBYxqo~BZ-FAtWe5Zw9{9B*V|DNfjb!}acnduBDb=hZGM&lJ5a8b zC#y5X3oo{8Uw>p#banj;-)FGKb1k2j?|Edq9oLssELsmB<4LphO0tQJ%-Z^UC8Ld9 z9P>yjw5GN^`0^U%M<^ZSTip9#&(2UgsCn}ykP}~5q}FBsShyM+H(<+?38|+jFp~$4 zF5KhmOJeyO)Y5iH{-S`_@%dZ&lKvk`UqmFK`5FFU@%Iwgr}qZv4Gs| zv3y?goOnq0%Ev0l_ut73=INu+^sWY=m6n+JHK4;g;u@csL|U&FuN&4cl6l2abry1X zV7q*hU>h!_MAH>wHwEW!OVI*aJ3Rj$y)?m7eKyKkY^Ld(@zp3!*60ApB73Z)_JL3= zM!K;S+Hr#_*LytKg0ojW7tlt`Okfsq7O~Kc6&^2>VrlK|wla!6Unw&;-86Zw|ZkkieR*a)ZM?>p5#U z0QhvA$kay!5DUdeanfn*UVtL|ASoqXGh&k9zcUkPwA43LPR}1fxAeQ{_+w2i#I@j zgb3voaxl|75H#&#{_Y8QGGne4O@zd%Bq&Rxy91hQ_&0 z7a_OXTs0PdR9pEw)S51Q&xDV9qD5{oIT*C?B%;Sf;72ZTyo8Ip!IaP~6Y1{q6R4O6 zhr@t>z@>A2v*k2}kD^4|q=ke+gR3>4;SI)&2EMzM-G|yE3CUSRe!4IJ(6SHp5Q{k0 zWhq>RnWN9MRFFf+FH zPIDM*TG!4HVVWndlJS$&AzX>4#`K zdl7Yfq2g(O@}&J?q=$UXpQgY+YeXpxW|sEeh~h*FY4QtYD|+J7 z;jgv|b96dTfWk)^`Vi71yqT}~&%HXkltPbtA|HWe!%N4-!m(rH zMnt@2ILdw75^4X?4BNY5E7gcRIOF;Dwb?2?m8)X?_H8;gZWnW9z8pW~oVLj_aY&F> zU4D}9E|9)py!va#P&tkL(OA)T=GoBomh|_wS8-jTP*d=)n)cTR@8HkhgcI;q2`9)I z3mXuVK)#xkL)%j;QW=v}ms~28-zo9vqHlN=!w(!-R1Qd>tUg>fXF++o|_ZnUCUY}w>k+iF5j=fWhsCGX)kU!1u+6=1j#kBXJxUqAg7 zq5hAt9(s~ zs}?ThQ$l!p?h{K2NIM2Jg++Ug{H?tkIDd-?t6X)a^>{7qvSW{`fR@AJ9_^K7hits~ z5u@W^$$~|6NymaV;WQ* zFg)YfDctO~m&|@6g=icipp8x7>r&R#1MJG2U5LT=P`|>ZUo3W>_4XYw>fT*~O#?(IsCxc zNVdK3l5jPkcOG7WNdpH19(&#oXm$XTHcL>muAqH>HiiN?T((gGllc(EwS{s+s%*jA zT6Ss~G;opV4aW+scSvM_l^jMv6Y3>%m7V^0dXzr`5w{W$Po)5bCGhA(B10{mYM-Z% zp&?%?-wbU_!MpJ20nCKaeY(3%H=fiB{U5`L3^7OA@C7!0$h~BYmCpYRyE0&gb4``51Yz8aWdq~o=`6jY!qxC z;qp|H13XT*&`&q#e7B%^2GfakZ`Bho0bkJs7rgOcg02Fg!(~C9x0^{G=I+oUV*udTt1-UvfbnWh@t8vqJp%P5KExC!= z=N;_}pwI6c_UrE>4xPwhb9~F5*6)B_b2_m*%rws9J@Zwi6uuo;&gKD~+s6gqM5-_c zUBrE$NoO!9ZP@?(%IKe~U2kE2*{4z``ean&t{M9KY*j!ua}bWYP`Xl^vsj^qJdR95 zRzSr}rIc;m6}IX_BKm{0H+mQ_@}t`yFLxEg?SL4Mhk9&(_JyD)C{n6v+h0;?|nQ4^Jxcz`{!o^qzrcT)!)Fm1n#(vUrQ96%v5)tjbvG+Xv< z+FZ6TVK6c%8HJKpp$5urPraNE2HZ0Q(YrkSs-ApU4{G?a{rRYO%+$cVW-)T5JZa?S zP2)DG!L5C-KatoCcp35c%^1#-sI585BMyznYJOXgz0(^qPEfYurm>Pot>APHb)mVA zDv!iYpq0`2&U#895Jiq)84%*4Y__Zr$O@%YQ6>c&@9v;7daxxXFx?j`88uIS%VL$F z{PQojYC5#*dW0GG%^`F-K}0YIE3YA$B$oi^sKe7dz~KG$_}es3XWZWcIIM)=4)s5) zAMmqxM46bjoDx>ji`|0ihMprkFbO<5C ze-MuNWC-5#ErZ{hT{D_nzC?pdNn)Jtec!(%q94&c*6ui$xk{%KB7XnTK9KlpDny4r z!XWNT;CvET$rDGeS2viqC-m~;3(~hB90C^V z!h;_B3!k|(*P8QN&u{j;`S!V6Hrdy88FOQn@zchHg@1VieE}04qbms zL=7;K$x(HiFTC#ir3c*zYJ>zbk(=K^g(i}GuSA~3yI>Cv{FtQJSU(4wSd0!Y!S5>rVRvg3>=SuM{P zhJhhXB^{WXWZOQC>93}$$Q5#f&GaHFSX$i+NmPo*5Tll9wTzb1K*GioppiDW*caqW zU?t{}A;Gn1o2^#zBF|b8?=QCr;Vn0hF)Yc^03}FzyuoOTau~1%o)32-oWFhigCqsN ztBt}B5$_GiC4s@38~^iH=s-a0x(ZoL1rhPonQ{73y3G~ZAC|(uQhz=j?L7TJ$YD zPf5M?cIb<>VTBD0^K^@UA2x4GJ}-^T8Uq^bd5rf{b0fQtu6?DG+(I^SE(g9}4?P`m*77@obz#AEdMx!E$+*)8$ ziw1wPVn8gJ^2`0#SbB{Y0rWu`*y~yzU(Rr;XT3FchpjeK7vS!k29`7owoQDXcN`S_ zavUwRp;_EmKj;;#jf6vk_16*9#Qk>yC`?g?QKXsP>4SDU@z)md>cH2tCJZqY4Cm9Q|twKUe2^55FAMH7?S)#(a zzgMq6$jw$-5nwI-Op_=OHnp!xtUP;|iT$C-&$_KJsTz+MVSD=)z>LrE0X&QUgU_He zc!a^f#QNVm_1~j22!?sY&%^L&prKK|-BU9^_>aGO(;5&JHnm-!MrOPHVKLxWB#trvtnE-ppa?=WfVY)yFCAnA{ zIi&l;Mb!9{M()}({B#Nv@fJ1PjdKKM?%dJfcqj{Jt$Tq;AIBPN$oUd|l7j1d7a?fzw1hPFm{gS%?=OJaOYKb=zjLn2<@qKRU-P%HLf#h` zy#A^VKT)BN{)-sm-SJxkUKl{N!@9XS-u_X@XnVFv^=!6-q@Ww}8W1U1AJspUJ3khO z^>!dU0cGOTt(*MXmlVhOvlMlfYUymhOR_XXq3V%BSV}AduzY~>Kq)9yp_{DOe!jj& zuMqxDujL8v7Iq+sCl+PzqtRae!ZsA5W;>Y7@)4CHIwM;sLX<@6dFV=X(@aABWYB$U z;}!<=dOBzr?CCQYrCTsvg>3l4*E@ZU%(mao29K-#3z!m412^KM`58hjICz&JHx0xl z!1_^&y>hJW?$)w-1_iua%`q6B@h;&48%O4Av*zp1yLx7e?Ma-~b6ikC>uouyW)r?X zas}g&Um1xdQzPpwH2JtZk}|XST>*?Tqt`FIp4V@vjAO3jk@ry5X`4i7=pMILMipzJ6s~lWzQMnfNK2M3E!T`uGd1@J{z0K z(Qt9OzFe6$xFk))N5xXJ8F^;bG$27VUY}NSxwdHUgV9L*shw=4Lf1c98U?(+&m=zL zJTwN$(>1*@puqkmH8a-61-L_&44OH!EHlz)8)Z1$QOZe4jQsx z|EivVp$~uoZbG)0r|DYu%-0)5kyjA#Xybtlt8HN!stB3M#d1ET<(7M|cniybzEGUy zhUw}`{2FEJ8FF9jp;uiYQzCMp|MhVrHi0}ju~Knp3diG0j~DA;_Cq6cc;N8Xgea1l z;ZnQ3Tx3FOba?%wP%0m?>JoI%HrC$00fzU_%n3AG7XT<2YwN{UCAOQvi!r!z{{6E? zN3x*#61RD9T<(-T6*~WC$xkQXOAh&Xe^I#nhH=VKgqQksIP`;V}cZvDLy^6@UU#FGH{k%=M8q1S~)-!s|z*kA~Fz{EpUCu_j zu*}tkvw#=*)4e_-NjJZW5)Rh(U{tgPSokL*$n!(!)1I5W>xiO7CTa;2pg5=_7S-c9 z0VK$yS1N4U-sEr!Vcr5&z?6!aGZwznA4H@SE2%6y0XlKhdMoTFNY)Msf zGZCA6vlU7fRG9f~T(mK)SpLDZpn-s1@<1RY*t5uez{2k3fvkmDmBCVct;K$p_@!j@ zC1ACX7TE|;pP}m8rvQ@>7L!3EN}gH;3y%05(RxGZ#T96d_hXV{eB2T*(}thKGa1Z-c|( z>N=S(u_AA8u*2}m%+Hm76#=6ZPpI_Wnfkv7Sfg8A0B`!+;%P%DQ*Nj=ezHV^+ju~K zNUH2Lq`s`t^#84yV;nU>XMZ?34@k)%ou6)SjP`xZ%d#~&S`Z^VZ??|XT;;3n^r?a~ zsGjf5=g|1J{QxhTETG69P4`yyreQmIVFp^)U>g3Y{!Z#hK%UF!%JqA+XFz=b2yirK zwN#_H=IFmf2XE*l`0Q5Zlm+o$evL>HtDQ^2CsIz&rAJyHi)q2Z25c89c8}ZWH#7=q zl2F{8ltAuRi;k}r5e0|iGYzv@W;Wl0Ln-^hDWi8UuEvB|9iJI-5X&P|{7QZtSZWbt zhMB~2-rygpI^4b;OG38bBN77-Cnhm9p(OZ!T8IDi5I%8UHR6Yk@g5Kq>hk+2z{B~i zr617y2bF7d=+Bd&&E<)w$J#*OH-i+0O+WoINb2<_+$M6zbf8IXFoMKkF<=pjNP{<( zr;<`2kIx6vQjS7~UV-OBI4gU7DH>Usd8uBXPo>{=7&~bp9zVK+N#A?5{bK;5HBrkz zRY)plWmm*RbzQCfv*wt&R33eb?ElBvS3qTzc5NFdB?3~?-KEmqE#0kjcS=b&h?I0m zcXvogcXxM5H~cp`l=Q-!@z4sNoSxS|9y6<_Bl?5OTuI}y6%52KB z+(O6T2H0L_b^ zqei3lYCoH-S~qhXoD5`Y$AZb4X&b+!XFtB%gB2=}l=_)@stPT~D2r6@3!|oUtg@Av zjaFU#-nm|@bE{KIkLAVwYja0GJbSA0!2KO@a?-Ku+6WKEtARj9lNqfs!89LRe^Rd7 z>!W_XgRPGVWh9a@`0AMQSmw%A<3Nc(G>J2xGZqWX26sq!oS_csWoi;Vz5YaRc8(bn z37cnow-ZSGR$P;CCOZ=%QxLsBvEk(5gu}Utg&q0*4`AEj>_+m`ve_97^-2)AY?~FW zFBVu?>YUC(B$8Of*dLBa<~?XeVlUO}C5k8M9v*m4Xt-G-kLm#>EAn|y?_o7b4%YAO z`$^cfa*b&>Mr~$iQls@6O)98!s=S@kKLeAARTg0ScgMc<4`mPQsX|RF_eeErm~M_` z&V&b{Y$o-FlZ2!IAw2X_;pj#DmLA0)i~hUaQGKL#-}o(pJ|>nk@aSaraoiIjWU4wI z3A#93pF^Y27}dZ7ZkfrNLEFVdvGwswb2@$f5Pii>iG(Ssm?7ee0fHTXnyT|!MyvJA zN#@7dSzs_cvdwi@zUmm$!GPg$cJ}y!p z!2R)iKx=Lk&Yrm|AvKsM_rH zQSP#be-9C^Osb1)mnOIojvW0s26R4m~8ytiuhJNeM2|fx}%4_;F-lw3>n^| zv42#~GHD&m8;_d}f*b?+dk=@!zE2?$!-_pxQg-1h)Ri~Gl3ZKi}pL1p(B&MVekUtteMzutpv zzcI}lZqzm_l}NLD6UR_o>b4q&WAmth)yy65&Bizm!^b8j;&-M)Y^to9wRQ;v0s%w< zD0L^aKOnktttgZlUliV*7UsEa?x0>Q-15Z)KY1APjGecHtKzb| z`H4m_QOHYV%*TPo1)7cIki9^L*X)qv@k-`<-fQv=sv0dmcK@ENe_P z|1=G{Gda6!wf%mg^8qf%q5D#}5;PzzpFId8yjwGO)u8u7LlFk(4>E0+bRMV3A29J} zd$ZB~LtfBGQ)=!b8rZ@BTm5TbLrp^{J#bv##5}CmiT&~!#Kq(vsUm1H#Nw-R&*q8o z(!%lH`96RMvs=J}{^zFFAo~YC`5*MsXqQlg3_Bq z4#KM3yb%ASj8x%0T;-mrv8CIZD^G(>d|31BKWNZk@hAXuPk6lEZiD5Y{};$||5BuY zBJayW`{Ru~0-Fjr8t84;c$H^^Itjh3bBw8C(bd-XpPl^7z6tABISoJ}Ks^9VzsC=@ zF?H4Jbe_PWv&vK`)G9C-&E~||_<|Y{EGrO=x}egK0CMZ$o9!Vx=~>dA?fyrY2{^G2 z|7`Hz>q!yMN3@RjzFS}#Etzv*1|h)x^DXcNzzXt-An?P#5)!t5BqV&dHAIfFe!j(m z6aFh(KpZJQ!vjn-Pdy1n!#54l*7i|HHa`!yeO8buxOfYA;1#eTPT)#iZm*M&`Ds)e zy3BF`v|0A%L;21c55Yg%>puvMzwu8W?*Jz1I0@0}pTBN86Z|s@soV}d0?d2xz7`yh z9{Yw6HXcQ1*#(QrRVwI?v$?+-(Ec?do|jJ93M%RnfFKSZ?7br zo7`RPbE(vt5$;Z}ivd&B(GM7Og3r1>;bYrw&PbS*L)>#v|I5!uyjNFU0vIkw?Df~z zuSXnBgwra^>-ErNXNs259r6~=%S%*ANLA&2@-g$#@u8@oe^RIDk{d=6x zKWBFNW9B?~2>B~FD-20PQ*!^w+}u#km&g7%><;{mw;29ft$sM4QagU?PTYU~-+z82 zAPSe7ddvFZqq9MT%}@6F4*zT`H>e`AH%^!Qw=2AF?qAFc2lN+TD2K{Fi-Y;f%cxKU3F|n#l7FSJ{yc~NzSBVW2!Y>K9}O$>=kw8k+?Oy~jnW1M zlyfHN+iMA0b_vXXHpC9XA9y#mtWOYsz0l{6KkIz0aQ~Wze}Cr`{&%O5f%KPaj+qwz zUVJ)avk(TT_umlz=|LcVcx$L&aq8WgS3O_!{X;h0KhO;H-#_5jwcsCp@qWcq`}bQT zyn68~g!@kE|F^rp=i2{#kxBA^=c}wHj?GWZ*YD;57rfqo9NE3P1h~_FKM0LLlYBch z0)NejsZZZ8xcq+^fd6e&awGUV{i`3in}q+EFhR~1e``O%Ut8gj1F_}b?*4v?|M6mB z1oWQGR<~!L`#+w6JL`|$3ze#dGC=;bZ=2Hp7{$>wy#vaBwdnucWWWCgiog>7-|znN z&$THGKIE^33%usfX2U2X`rF-qH^;y3#K(eJDdFNc@b7aJ${#}kkpk^u@b9juLjHBe z-;}9DXZ^2}@9z`wKdyO*_Wrd@KX^#^$Byyp@E2tI*DJq-{fp*ysHGs(!ZNIn&8)zR^MXe)BmeQ|J71|AH2V=@%&mj z{^JFIe&ai$KUNMwPUgQYD}=wA&9Lq>^HX;zqGV2C-eOn-jNju#1bU?}eni9xm3_9E znaqJX74?rN1o?^POJ*`E4Z3)w|5%KjVei)%*e-)#oZi1Zuv*~9Shp8b^Rz5tTx#1} zDV4v+a|+L|apLoR)`O9!>FL809xX!j!Qa21f9*ctDvdd`@%lN8VKZQs{(4ijXl^B3 z$m+dFp8o%6Av_yU3`MWG9%TKGCj(u>O!$!Dj;O3r(<;i9d6|JXi5nD7uWipb>m84x z0MKKzE7QH97Qy}QX5YiEy_q(x(j(X_TH}5_cc6W#j4r?q2Jy5e{&HG#y$qjf7#@m z|E%Ozy#@{75!w{B>tt|RmtNBRq76m{gy|lIRwKwDf?{XVsbX@uJ`S_e>wgP!2hbHY zd}#!Q(%~B`hFp_2p)~o~+zo1|vjg*S6hA@AI=9F`s1FOs3dqAa0*$E=X=GVHN_BGP z=BCKLcJ!;QU)#%p8ECP;_2~cc+T;Zo_9PfY|C|*~_P_I%)0huQpFhIqZn9n=t09ZO zWabY*4s%|Uc;>Dkr7Hz}4Xmi;N?kFP#ZU9lJBRDVq;j8)9)f5;r9bH|+~r;*y86Vx zd@Kq08A#7RB4N`dHTbLBpp+j0xA+X7U=^863DYdIgjoFPmqx#e z?#aL*Av(YTE*XHSs1zP3m1ITVGEm zx-#Fh1=Z_G+&w;+Qy!;__Wjwu5U~0#-UxAfMg@aM&;+4oJM)M~=OZlx%s)Hu@7oM_ z$BQapUM!!d7B}<3HchV=!^cEB3;X9J{U~UrA=$#1mxAgYIDGz8yaAH{ZGS$!&XfJ? zgX6k!r2t?lKHpot%nv58S`rxe1#WPbPk&GRKQ0hv{tTY0E>bxW&gYFaEM)V% zYw&S>n#I%+ys?My)0?dmu4CX)F72gBHH$RMQNPh|%(Qy)h252m*bjGntK9MQ+B^V} z1LFpGlPe7KQ4S&U5S{hncn)kiDH)Cb+^c-jYZ2BT{d1N6>xmYIAb@NofKQnugS^*( zrrT_qW?Qu3y$}SD?v^^x5+I9J>K#-#r&8+$hISG_H7f(;Rl7}q4r8iXb%`tx{B6q# zTQo(9JV2vWPf@Qu9RR%N&6x|>2z)-)t}qVFNFZ1^lqqRknOEP6$z(S8aGuXb?s(H{ zLv`q@2$}ZxCjY zDL0VR)OX}s#&RMR>D6=bE26)K!-NKag)kS;(b?>#L0MJ*xl27&R7!u#cHp)%#`#+w!D3ylvX zapD+k1jPO*{uHZ0Vkjl;#GH0xKzYDkpq@(02tIueD|`jMw`(MzY0d zb9Gs)n$N@JfLwdrX2lCod=da4{)))AduFrQhT%^YhA+Bv?$zk>CXezn+Jg{1*ZSim zvSngmo$~Yqi9jGyg!qz}-+^zuutEhl5L3}+L(no+DWH|rF4gPf_J&zWk=4K6nDD2w*=yFlTwPBx9IC=cmDi|o4z}B86F%GH z`U)H-qdyZ#aDzoKeTW!FcBP|Hd4)+(tq zJ%d##Ydz-RNk1fRvybj9TLKDbh-S7-WO_jxBU!F+HHYiAtX9|b3GB8}=T|+qF10dC z{Lp3Bbw}r&bWV_P-)!UhB9OsyB*o1=ueiEPYRTbYUfvs5VIze?0MC zGQqx6>j`<9L5qq5Au8!igEg1>i)XkTt`rG3Rdd&l)>3mblhj-Cwl60+TrT4Qe>>6SU|Flc|q(al-_z1zGdINpHrRC zG?#mOBJJi@B=!zam&i85TXi)P)vMBD+pO_vlUOI^5@K*Ib*Z;Ki%OX zI*X&v6BulJ)K&Pzw;EOvYVB_DAlz-B)_!02!=i^{*`cl&T3T7QY?rpJ`3+E8DmT*5 z?AD$cbTe}XiOSpCbg}Tyz|exf7{cCZaWRebuwlJF$Tt*6)(fi9Z$5KE4oD6u&uzS| z{xFMrxxMF7Loq{*%kE5-E0M$)IVJ(VLZCY6%^b#KV;AUoY5eycu$$=h#Y!%JmjqfMyp0}Djs`E`;?h5b zH9AiN*5+I7_6~7OMQLaJkP+WLbthx34xp|elj3oaZag(t59#L}g+&2S3P3e?7%lv2 zM^w4cU8Jc+;?wR_S+bY^iy?sEG58)-Jw*MP4p2g6tHfFNn(Th6=T7rid|Q_*)DT~M z7Q<7+UI5De1!~n4!)v_>f)|HtQCF9^R9;wYeXU+?U&@UY(KMk1Qee?&!z<6^KAc`x z+YHQ9>gV!l&TMUuYRvTfsRi&I5SF+Xpf=h*jascl6$D*BS&I#CH&~95Eg1^(e=&@Y z-!<%3d;u8EBQjM81uTXye#m!xPN2~5C!Zy9@m5{Qb0K+cKNpd0;6w{wT5_3a#$_Kh zMf*iuQloK5NEQ^H%-dG{BI;R1?1fSJO2}kz8E-5_tKQwFg}#|~1KjEpwHo2?wp7Yd zbw;CfVrTn!uhwnWCuO@PDt+@VTbmYnAD}11_Qdi6!`HOp6AW3vr76>cSFh(?{qE4Y zEbA#Gl~Z+4PG5ec3^jmcZ%m5*)_CYM22^|RCn(x^=dTrX*M12olxu!sbW=JRSz#uU zf{V_kdhzLi)U!!oPApAA@0okXML(HhiU37^zgQtFkNhhhE%@{Ft9B-ux*qURV@AHt z;Nc|^DlWUlk1wJX7T(&@Q=b;+WIEDxhjxp&iyW6(WvH?O8K<#1Trsd&?53zBuyy(( zLb{++MmvgSb>+_b^1X%MM2lw7a6k%&A;A)Ck7tX9XY>vaIp~)~`^NYM3rGh>=QDJt zagk|eR3R&UUL#jLGj4y7^Bi^3GKmvFfCOSpW4eJ#WWH-AZn5O)R8fdW8)NB_Ie72<%?XjsG5cyt$vC}JSQ$-Kzs)i)1T$uk-~ z@!|(oK&EU+evpdCzA3e;Z#SRzBl;I7A^Cc{7DjQo+@<4bl~GEW`YHKiX?nLon5m*k zdc`KE9z1fg2G?aE~NIX4>Vf(>yTS_tEW%s-Y%4ABeZ|}T%UrQ1$L$3U%$^6$+ zCt3M!X8~zvrc3+>hVK0o^7)gD06hdWcsdIPrt&_*V*knwpw)B^$o~~E{4=HEUL=yt z{Y^$@L9tX&9)rG!cDBwjkV2tA{15f1&57dhk*_hG(}GPBrm zShQZrXPaDVaqB8ox*}BrHE{SlW*1@SK?EM+PU^tt%FbV?lx0+EKfD$QdMPdDcD9E- znm6hP%FR6D7~`3odn6A-qQ3P>97XMJ{#ewODXX%&AP@~Bh>5xaCRZbQ0#2+>r&#HT zlraU$bsQUux51H$^5`&P( zwXaK{q;WHL=XlI0QMN&_m5two;b}r>97>u&mO;qcUgL8(Zh&y+I%34;jMd(UV zmN;n+LF?!57N>pG6!bmE%HJh?WW6m41N+%)PL4%BL4>LHC8pHKiX*)&2s*B?P^3R? zabTaf$F)VhS+LOSAQMGzKY)gE=O9Hj97|#h>(c4s1$x@irls0?zTVbZ((cXl>6WnQ zXP2|8UDS!>XSc2r+FJ~%V*;jZHx&pTqmk{QQnzx32CDrHCC(PN?_R&Je&4<^7S6;A z71Q?Kk}x`#?iLxl?l}G)rh`rBS*jT_whB&}$LwK1#N|FxFR*JH(EMk21LfIYA})xB zt%JP6NCSbjNU6vABM!KAqtK)NE>#SMy|O0zqUT7HQE$ zpn&H0rssZCQ$xN$gcTO8J@a_2R~5b2gWXPS<((Kp=gn~7qe=CUD^6z%+)a#j-N^*= znbw#(%E!?npP9oflCR@58l3Y}{nhtt>`bz;kNO(#8d5UyYh%j8fQRlP&dczLS(%ea z>~){#JEjUz2@H_W&~w`?Yj>E>heNrb$9u(865zHJ(lF$^jW2*pW689-eI<{Iqh1n! z)q7V2ny5;%yY$hP8!Uz%S-%|DktGKq|1k$m^=;uW0#W_%>&?BNu?gkhk$wXcD!b*~ z^xheV=$!1D!AUVDe&FOS>MkW3mxPXV-k{;DjQJ8KaO-vWQ(){h9+=6}d zj94`)Xr!=TaWJg`7a)S>J$Gvz49;lBd&jxNb0Url&vAlgG36JG`_DddLY&Sm{wei6 zma}|C$X7$(ybC^uygs|l3C?aj9-HM}Hd`P8sZlL+d&$ZAq&7-reQq+<5D*Y3GUY3JF1Vi=>);myTx=%UDcWd!+W7@o3B z1-qQ{JT2cI$Yy1k@^4A}1#1+vQh11a*%y{_#Ka03Vy~CfQ)m$wC-|8q*&gx1?7MFQLxN&U!rY zeTUEdkeBx(9uE=`w}riZ^n!{;rz4_Zjo0T7yi$fdyw@5c5%d?etc(!{( zd@%5mI9$n|sIgi_qo^{*R)uFT#nV-_?JN66@{NV++2`K-b^;Pl zr{%%93H0?Va!F2gt~9}Oshi94;GEf7`y>kaY{KD8@dV-3?r7=mI_C>g6xwW6dE0Mw zcoZ^UlVdaaS*vOWfk1zj@~|L%t5fplpnLW%G9uJer5G!|o_N@22{>%iV~r!}JW+Ms zJldOs>uTiHixGH~x0gWubIw>n>hK(TV`@SKS*%JF<7wp+YXcx{*ZMr%x85196i_)Z z;=4sUgXFaB@LCHj&UEU61I$;Z7AK55z+P)v#VK2enp)`$dtc3I8J1*ELBIv ziS<_9>x#rze+mCmvN?hI4WBH&5xd1Ei|G-Spd%g8E2G#azL=7njFb*LMDfIEkn?FR zgrYHd<|FTjNR==f%l8^i&+~)fFYp$!?o<3DbiS7V5+oQwEQ*G{Iein7MHn2F7Wh$N zrp=`!IXhF;i9%!Kd~yy`c1y|94u0LoY-eu`j5;DH$c1I)Iah(*i_)#`a3Gd%ahajB8P z&vcfF|Nf*8c5n$CL*y)9uo0|vMyi`?_c!o0N17$h==*ljV5|BIXxaugmjsg3&U(i; z5*@MGn~2C$_;C7S;UW;t>_~L5qn^lTD=F-rjczlo%(bhc7>HwV1r2405O=G*;J+n@ z@HDHhms>;*%$Qh|VAAkwv=NA16kRvq(*MHU=dCdAutq0JEw%U2l5@e~7`T!10}tI>8?sBN8FX zSUy|Z%;}=b7K5JX*s)4=ow4fpfP zawCMP;XEmx&L#fCt`gGYQ_L00S(@rukafs1H6rXP*A+#`w#{GB#$m0h+*;}iDZLl> zXMv6CUaPwO>?k{Ohi2yu+HQ&zHa`%>HkG+pyZewTevi$fiozoCwQdH5A%nzo~6nLjR8VV~04AmUIuj!sz2P?(PnPg!~DW!VBIf4QJ9!>?c z8FVg3$d|LVysbXysNv={-=Y0_k1mw{G}-RnU*4S}mQ+hU*syB}5o%wo7E?aSY-Ljcl(!y|}sN zs?XSiA{Dmtq>AInjKx9s=rCFq99lG1%rf1yLS7hBFrAL-h=1&qy}smFva#Qc{l@y` z41TqYL+IvAeXX2TRW$M!4fJJ6uGY)MODc74y0cx9{SU!e<|k8S)GPK@s9Hx3%_!$p z{bZt)Y7ErguxI?5$za*@b`WF9tNkI5>Nk|D& zNDIGT5^kO!?TJ-e>(OC6Vk43NABAmzdDru*ra`sFFCN zG0k?KeBm?dFA$d2E-pVz4NZVKT1YP7ZuDNfHGlk_))~w5oxS!)JS`T=ek71Ch~gzh z)*eZfDy{Z54-#%~>SmItTeWv|vfv86b7z_F(3{=&nKoZ_()fxR43*^CezOtR>>Pz`sr6V3e0LD@4Inzvx@-*c$Qyc@oEL}je{2Zu0~FxUTskYv+Q!wlDPQn zviyo_f{6K+b$aCiBMsuRAzM#&FX(KFMkrr~B$#n<$gc}nn_{vO(ZtYtz1M6tuh7V? zcqYykkY=t3)MP%hNi-#1-b)P7_%88z?FcJ{> zIaAItskk`KFI4C~2}vhvMj3qd40BV``Nn$Swx7%C*28X(liTSOJ43I}_JluI6mtis zljgIJZRE8dSXIVFb<`?7Ic7Suxp8zIwxXWQP_3-Jviq7zfgume?9eK`e^0Lc0Sn*q zPom%7$`%$TkAN}=VJ2_-D$h!Hv@gj;C}J*O!)q(QXZzBLtT$}s7KXIB`x6x*Lz(dE z&{0Uy)S3dEd_vMgL?Q;;QKJ!fJXzM`mXF8Ns#XNg(&XI%p$%Gs;DNf<`G39Gkv*HLU1Q>BF~m-Gp~KmW9LnW z`|RE2vzH{xjk>-3X)chRRoQ5YOz@vPNw z3t7kzC9ek5r1*t>`s}nxCGNG(I*q8~n21pAr!dr}s&i?4mxY|9GlIT{*knwV5c$bX z=|ndu4}X_#hBy#s;Q8ho0&6+(Hb$|+#&TNPd z3Xjy7jTK18OjTHoQDPwS=;&xxuJI4CFNp6%u(-uwITh|KS?-w-t)~4>!bk` za3O04Ua9>v!22tzcQ+4him!$>>``)ae0PVG8-z-;!hdy&`}OwbgG_A&b&E^WwN&YQ zZL}Jz)mWQEwW@a+gDtuGODSn$xgj=Jr`V#T3g33dMk8f1MTr$2xbP2W^ha&7XY_)! z9}ufG!RQ9|=wy-&S|vL#8yDp=D~gxLPcWJM)nBnNv#h2O2d;Hg9aMt7%f0GhtnD`o+Ue@RXW#p@hEZ|y#f;POt@z`|UyVsC+ax~S_D+AY z9$Xq>HK54nu#MkhMM?Eeuptn#z9HXK8KewkQ(i$w2PK~N5tAkI8eF-U7q{1GlO(19 zbiH~DOFQ(fn|9-epN!sgK+iMPc5~yTK@L~dc5kcyw}Wvy$}5ahE_pwEdst~AUyWI| z0DYH~5I-MX-*bsi9^Cm&R&GC}VZN}cqB7Wo(C2aKf3un@(~W-1Na{zA{K{yW*=B_( z82$@>_&s4bl5z_*WHd^82>{wtJ{?7`6pZCdQa)Jip^BjsMl^7Du5LZzPe@A}@>z_! zT6<0Aj(uSS^IGZDM0pb+d!;@HSFAyV)iqJo8e0_+Ei7MGn%|`=VA~MLq2fryY;t(ItJ}peFyzAm{XP$1b#ZjOD#f@8wbn!%_#>YyIc-$Z4Y+lYhh6+ zm%iGe%^CY*4zLy--U*EYU7l2n3Z3Y#{RUt@-SX;1q=)eCm7q>FPKm=Ih{{@<$L{m> z?w&%Mt4W0`?+@;r)alzI%qCpvEIjeU?4I7M+fnjsc$(9>MW*bEYpyD>8%OgX#2nD6I1x9!0*&0U&Ksq+YPzd6B1u7|4&e@#* zc%60~&r&Me)cRV6$}qwZKgBZ_6C2?5SS4xH-w5@`97-Mxw501oYDp78?rHbtvFk`v75#N_x6IH ztuGp1HB*A+C4ma?lZ+$rLo7uYA-BS5Ix0O@xA54Tll-{aE%5h zvHSQ`Y03TK-qvk79$f|xeTgmPa~o4VOnLSJnORH&T-;};$gPY3FP8k_AcV~w2c56F z57Y8JIs_p1q}KuC=v6Vht}qT$&oZ>}ll$pZ`~NYW@|OzU6W;hgae5Dz8~wCX-_&@_ zJY7I+ykpDdLzPVDl6Nm-x$YHCEQ5V^4}2(|)pAqCFCbcvVDaNA%oYr2z z?lar$4@GrFQ{yjZXzaljtJ;4H^c=XTz1yES9 zfJkI_6xHpL57+9L<309z@aVOB(-9i2!ElCYncnWx&8;jBJv(zO2CFQa4H!}eQQsl13M+VF2HysZ>g@#7A zDvnSzf=aE*2Vx6G@`V6gE*v=Q znK&R2mN~{i>R0D{@)Yh6hq`+-Pa$loa!?al#&kjKtM>S<*6WFA8K_F<_sOw03{S$Q ztlvzuB*eq4NVn_09IR0@QWrC=SAd(Qn;8#jbCQx=;%t6F6}&uogf?RSiMIa3$#%;E!V<9k@nj>wt-ulseTVODb3R>YPB5eyi<6qXY<>EuSa>l_yY_zeDIIBuQgQ|sM>?(hdLsD0xeiMa)89nR<(f==*Rcz){8lY28PmyEGS$?a1JwU*6TDKc0(EB ze4t93fyGiH+Z!vN57W0dTPq1n0KXog(F|pW>+85(V>beWlEXP7fsWk7l?lM{p-Z=CmhE*xU1`q$&#+9xYqqI>pdbJ<4oq`d(qj`;4b!tbuF zc-e*$yF_;N>&Ie+!iT0pfXSH5Xlk1qVKmGFDii1jcj3~vA*(Z0oN$<|O4Ns!y_iN5 zS>DLvhg-RX&b}Snv<(P4bI5norF#9DCzy=ghZ>1D*#dziM(X^adkB)6=ETsl3L5vE zOpB=+hoTxDZ~7`-HeNJb{75WuJdV&}ze6?6QjaF%t-Epe86{B++6J3hEV)|FHk3wzI2dps_BzVwOUgd1_}XSY$?J)6 zO>tLsooknVXNPQMaJoOcAa1a^=YWI96l2 zB|bbv!;_yNT7AU!-$;Q!FT%u{G`##kwznfaaIE3!L$M{AU5D%MkU-L)M!&s*^M<@Z zP%52T|D|LcNu={>rSU!wO#Ew2J$r-cAS1c_cS>@znneyM`O{VEd%i*l*(h=q1}aGb z$X$gMrsSX5m1Tg0W<@6fz{4Q-_ZJRKTBCWZ&MI?^H-g*=EGge`;3*)H&;sgHV4r3k zufEsgnYQlnnoLHP{7QOrqHUlE8OR3pvm&`U|*SGO5BM_}nRH$uP z%j`Qi_C`>Nl0bOz$nu^*NR#`GG?+s?4Wi%7%6ZxL64+@RNg3CuT+WD~k-~Mp@Sa5k7$>9q-1{`;UPJEBOLT^-Ce>+82toG~Ls^#ZSN&VfnHO}O8?E4%${S>uuqd(Rrdw)5B%1T#}Cg#sl!b(~-rW#KBvBgS2{vzBkZ&tYFLn^LHJ z{e;XkR-m5X1BWXPMEcYB%o4Iy$3u)Lff17;8p;D0GmE?ERj_L4hAK~QFG3>>`tafm_Td84ydQ#N)}FCFkMfrDP!v!ba3yitJgYOtzsCGOe5H zg@`Bl8me)+Z*Z!d*x;0k`PaOIUJ9Xy6Ei8()cJ!lQnE{Pxz#4GXgD);G2i+$yqhe! zChdnyLAOQHpB7B-9ZvSJ)3-+jNcwjtA~8_kXuO^-3ZcHDB8%UPRYakuVYLWlh4h|~ zk*99)Xb!wx9leR?IO{r9GC&{wHrS3k>I|%xoK5f7l3luwxBmf>zu)3+p(X+m1~tCF zchiR=grU4&OH5U*QK>S;Rc&CCpPy{;Ia=wC>!}87A}moAzSq{Ru5L0GlDy(dO zRpYV_ugu8qA)H^7<(gnLQc`Wp_b3-KnY^jLUcX;c@aj2MShjck;ZXAJECX?m5I~-Z zx-MttgxFzEGh}Yb+cZkXfx@zwMtD@s{5TRxkfgQ#+gH;M*&yup^Xa6|sf|f6c5_u1 zqA1C@s0s>IhsQ;`Rb{4M0*piRZ8}p&a%(qP;MMHAPdVs~ z_hcr6tXrl=$}F+}I@-$=JCkpn>b@3&l|L@&310SeFdM21j-%@C^On64k^-r&ldZ#$ zG24O9ctb_0>Bj9vd5fH|R=%MyQnR9&Z;#VQvTcr3Qe_abO=~6L6}5P@l^$t!JBwSt zWHEW5dq*88ZJY0Dqyu}O#+B2ooI1;YZt7)Fr*dw~Ecj^$@7vGhZJB2vB;Nz~4w82g zK*4*FFqSx;5Uh**32M`#qb?3t8bEFW?)Vr#F{|48>S>yuMBpfcLV<=Du$f6=EjNC- zDx~O9ZYem}W~*Wd)@v_M0s^*|X^?&N3Q~ z3D(f$K%@SY{RjFx+mQpTx0||OCX`>%3bVq-cD#vc?Td%Qs3;;km7|CvlaA2qk2hL* z@iKB*_A*37m5+xAm#vl{1d~goCIg47MzcW0uw%uf!_jC+Zv96jsXa|BlYI@9xst@B zJ`es~zs32@F@Cs~Vgu*l8ZAw?1KepcYHxxr`x}j|F>}$ny&@3@!`R=8{DDVVs6Y_1&QWy-UA@7Fs9v z4WGKE>8A71!18|@h#)f}&Bap`FX|3%Nu>w2y%*^4gvitIqfZn9g6yotE- z##&^l3Uc)jlIk)B3Zy}=A5a8^9InDo>LEJ{Dv!~H(_MkRHg}10$V^#QDJF-@P3)o5 zNwjVsG`{}R$N1~Pq@meO(a!0?emJn>`UhJ19^?jZyW>&gFslWfQT-Y#1F5(q-}!#0 zFJL?2k3z)^d6$vDTv;Bsfzz13%*%pcAqQqK>sCxl)jwx2-WJpZ5UFxP7a9o@>>dRiYqbuOu9No2}?Pk*h31NrzBr%1GweP-GWCs_i;?}CKb%)FLV;=%X zYcI?d;!9#jnegY~fM1Y|YHF*+v!@Nh?-FIZlUlnQ5>V;o2jM({T?hTM%s#IHD6U!S zfF*&1toi6Ri1MXeyZktr{4JExoEr`yKmFax)dpgrF6eNNd$ec?7A%i4LXKAB_XcHlC9KAl*^dTDb>Qg0?|&p zV-p!So(wcuGc2EPN5@VpqL+_zUC1j5C<4NxE`HT}q&vdvN5ILqg3M~7!X#Rk_8kZUUup$^}$Z(X~2wpZe1 zs@V6C%tC!q-YpK1a5+UE=B4jWLrvrgP1QPT(7 zLQ=i4De(HKADllVxOuWIlfKO;#b4hT*DU=Uohgy0CHl)Ih#J@g@w#&Ha@~Brd-vme zuj+m2`Wp8g&+d{yDf#FCo&{$@fPdXu!X&lmK@cQ_Q({9bX5b?q2Y(x;g_Q-YofTM8T@ zFd#f3&1*mIZ%oSmJa573a)oMJsFol|Z$#lct$RzQ;>`Tzk*Ymj^ottbHSvtg;jvG2 zz_B=ipxk|!C8>quZZiVUOwH7;Y8j+GB5f-jQA;O$K#~x|DA|{O+P{(>@7d8?v`7~_ z%51MI7_n!UD{a-tApZ}wt)EGc)DU`=5SmA8t?E8EcYwt;Qechy;bbegXNyAZgaX>0 zqve(5Ar%a#&0CW7t_w`Kv%O5z_k%A2!g zX8Ey)pMV0^#AI*1F%539Q}~N zTi?*cua>v0-!O0`2S#2uuaKqWwa~8d8yh`DEM7zC-1~ytx)g%-g7~dLtDN2!$AhFd zfzPo<)G^VAGE<;k`GO`O`o2g~$*jI3OD;W8VHmF0uxc7%DdSRF{}IDv{~TkYUtE&D zd)z7Mp;pQctweglRIL=qyz64FegAeu0i4rGx^+6^-M@#>YfOZzD@>ZoL#y!U@E2g` zBUA{E!i=Pt(xt;zuPz_paE44|M|y%nz9{XQr^PGMrx7tr!~`C~dzF0AuE&S{iY3(~ z!CO+{g5{AJtEc^nh1ucL59F!xZ42dQv@Sj*qR|f;q^tq`E17j*=8k(7#?!|iTlwy_bwvdc1nRAEf2dAVJ3 zqh}xA=6C~IrNTLKr=?rWUN(lt6r(GW(wFMP*&eRV!4L|-nvtVWC~;>?==a5^w@W6< z^u5yvqlwc~0=f--C-!@cIde`}$4+TUTN2=FT0|8NHlPT#vU9CX>yH#%o zFSjNZ+skL_Cx=3+^!jTo4Mu;{sAKJPjU&lS^pBVJ+BXk_~q1x&Rg=_&vbxj3vWkG>lsU0E5;6jvmZg2yw;ghi4>GD);Hv8>S=uj{! z^cajc6_Dh<-z&YITm zX%mDl4p#>$n;Tn*kl{y`TK)4gj&77T-^i~zoLBm-cCT&D1|Cp+NvJ(ePHUHtYI$mF z=v7#$5=|J0N=rD8sJ+S;4h&Lrn+;6y+g^tczlG*6*F^+tz8|x@|1{I^Ck9F~jdfXZs?_JFy9jx;rJmg?i3? z-*fIAaT+)l6}sojUCb(vVHo=dmwjI zsB)iK^ghV%!>(__a)P1V?YafK!!o=djEWFRxoBj+Nk{C~i3tD`nj!Pt8&oX8(P1Qi zJg^P~wQa!IR_^Mc3N*ACqGi5@b_W97-3^E%%p{Qm2tp2xF??I%yK5Kc)P7FXM{db*ZVUty?!sPnuP(x^Ki zLGQHrvE$vD16-b>u5XY53bE9Xw4ElZnajUu8d|60%uFSQ=u5wTneJicO3};cPA53O zCnl*g4aSr4U75|6mB#(zMqlginaqW)2VMlF@qxs%kcFs}fSzc2D7SyQcf4E1BITYI zF8E}4DA;&d>lJ$c_j*^Ibu!79AJ>NxGvXhxOZ-Tn*Y55xw`v|S%meKqL#|WnJ7W7P zb|b~FFnDB6R7e?<)uI>KbqxdIMpSkQK;j&f`-JZ(5Qc((>qT7evUdD)@_#Vs*m z{@7RA;>X>M@QZwLw0_eVqg1lH=f^nWJ1m>rtTj+GOkX{{KeCSwPg$FN8|e}W#gTx+ zcpU=|e0@p3#xI&z8M*C#ew55*?3J462)unKTap*BW*+nH%w;N;0oArJd=_~bR=xcu z@{+5I9kIQ+TE%49y2mkj4~6`km$p~ckC@Vk<5lA*l~S9aT{qd{$m1-U5n_*j8Ef)N z61{QmvrEQeRp2soki=qY7g=BlO+{?Kj4#!iTm^6qaW4o@1e*^8@^sYn7ZX0>1yH<9qDWwB=XiVppV`l=@s zN=30|@ydulMn7THSnOo2TO0OG5FD`x8H)2`~2!q*5Pp9ge+kby+293=&cA5{7We?Y9-H?PkT5>^KIxV^Y(w3k2^_shF89 zzQdr98Q6d#ed=_I{sQWxKaS^PFmzJCAFoRNMv+=}(M_`udKVl3 z55yul-5(LNIlGSBCeV_D0t7$ejPPg5^^7`x^3Q9#nA=r$Ub`uN&d^VvPoki6dtUn= zJDtbrw=)LC$hKnH7dUu%f6clsC2Uo=@M{=Wlh&A@U064ODRvrB?0CQjfaXV}nm@m^ z#m`?*o*GM~AGX9@a{h+BHM68E-Iki!eFknu-=k^v6{$S=V%DmI^w{#MJm)jVbRgHh zEZ3d5Z7~!{QSkSMuThR&zAX(*dsTIIK%vF`!u6;8e)ZNwC63$`F6enYFHn-9r6mFe zlr8z1&F5od+E9fKUr^tsR4O5=xsCAkr4T+I+(f1P%=FFVmEjD#hel)Y{?Rvfn%F0g zMM!`EPj)(6=)cs4vcf+!!yxS$;mC<#y%xcEC`l?9e0JF*eSU~#L@7aAYVDIeF)({s zr+c^HF)>3?bSU*HdWK>(HUYFSWW4wqj3K~D)uxfU$nIdLG`JN0TK-(EdXuX>pIs(p z{9wV892Wu&DM5bfy#_!JY;pH?35c^gT|!nEe5@JClwv57EA>_%0Os7YKf}`n)%kMO z)ljzPD{@i&O`{DN!NwkJfX`BZW{Y)hWVsk`+Ya%Sj`%5DMgE z!^M$uXPtP1167(N^m)cSTUB9ieAgF*P;TO`ouJc+U>zcWk0U_GupN0uB(){bSk{$z$Jq0dW$D#!P#&id$>32T?ZAN)E*-rfBwgzZVtBt3QP z`5_Jkx|l~{9;R?Lr`ns@dY?N@2^t>VL(vA8+jwmyhhW2QQG}_Ng53{2jPF|&DY#%8 zURTs5AkgJ_?4W38I?GooTVkRo9?waE%jTw8)-X(iMBTL_W)^_pUq+f42=jS)EhK;9 ziu%XSf^o+D2D?#Te9nslo{=ewhKAHy=W$B$SaQO&=WH@N(^gr)??zk%qHLl`%|MN% zE^%Zk!vhpxNds4zKejp%LP0Y@46g1a31kijbg`6iN>5c4Zpe@wvB4dtO z4<1N!58d5FJA>7VneY% zEsKl6Hu83Y?YGaE`0`7YO8?nohwIncm091H_GfB`az3ZR9hs?~VKFL@<=A4uJ$(v) zsx0IPjHlwtq4tbPJ>%UGV=N^SDER<^Cia4K9;=a%L_AUSnefb)q|S)Oi(Q3SBS3)7E@s<;AtsP!a6gyMYatmZ^QrBwO)Pj$LIi?>BiRIB2 zZX-2VRBU$8U3A*c5Pzfc2TLYpj zk)MxYqwuFcLX5xn=tHRk?I&{K8e7&aP5e< zG(D;NEG~(fI6*6NY}}SSq>$Q=`V2nQO$r!!8NRrnaan^GYII3@%F(1czDi5;P8@yl z!ftC$;WkW2Y})eYg_a4rmozdLe-`}lyvP7qmgUISZU3Wt#8HMgpt*o zEa_lT3S#afDeB_o_tB@UE3%D?Szu-Ti z6DV23M->k!1Z2QYFxE1pHI%={+2u3-Eh3d260h`z2irUrPv=_}2@B8o<+QiHBY6rD zTUnlL;+H28q#<)efr@>aiK^-JuOiGV(+WhZjc#gBuWP!j`e$UHLgG9a#fQ7Bzp?xm zx`Z9#oJg=b!CDa4v>HbXk~*kyAk3>%ikhIoW2IIO$wAX#gCCtq{n>mM_tHpDd-+Ve zGp$mQPR?eDDiRsMw!=t0OC>HA5k%~L&WU21vJqT?$A-@SNedIBks4?L`)p4Y@dJYb z`RK_#&_Xr&vaD1@oRv&S6x5k|K^kTz(amnrfNY#U@H1<_^qXVcEBh2sU9s7j_piLo zyVslmdnmT9afhFT3O3t{HC{w-uG*8WmhNkRLa>X{?9Fd2G+vD9S@kwi_-oBn-zyH} zr!aWdi&7AYn6s(FR{|?(yb!@~&=%J+60nv>9tO3x2kc+U~qcD1Q3q@TT=F?dX zO1!Xp?F`NPYN0*)TrE=&c|-Be4-9QAm&>NKjucjF&b~n3JzL zn@hp7ngrr&wb*FUm^IlP!CNRXS@zeU+1w!yYL#o+1K>#&w#kzB&%zLMiAg_&-jzMq zOtzyG#DWd(;?=4u^TBPjheAq{p)_!Bd6qY<{_491Lb1M*gPT!;0@!cgCl$0<5(XOf zonsILR=3)EBYAxgf&g1vF5uMmh+R{|q;j}okw_-;PJt$nkDb+gz4@nkmek7vG$erg z?DG{y-#-ez3C1RBd^BM-BPs2_Gn4uJY->Ra_uE_zwrNIwL~2_v3g>elAgZ3=c<|ki z-O()ndyZMBZ&{gz7{{zVu!^Be`dn5hvFTH3xBcfbkQsE~QhNg2l zNI&66VTI#t$b1p2jEci;9MAfMVyRRRem>SL73S&UwRMrxnyy8m`fVneRQ&3S@TTd5%VJ@qowi|PDarFAH06wk`jr4nM z^+S4lua7|zK4V0?l5=7>|A0?c2+R zBU4HcZ-yU4;83ab$wii|m$6CDe3H9tgE_gP(1nIl`=ASCz4BxeaI}R3`tPBo{HVwm zU0?ct5F0m{J5}@VCB2YhOSR#1NIC`8kg~Ag@mKjL?ov_h(i2r8EaF*edr>E>CE8W# zoX{_b?_L{rR{lKgr@eZSdUtnC{95(1FW_C3((r#do8fD&GI!O-u#)i7YR#8U5zCiO zm%~U|K7J4@vRM=FUyP4ktfa2-;RKzv9^%996Jr3bBU;*Z61IpHa)`6t$i-7KlfBC6 zov`bG2|4AAr_Jk_E-O&etb6N0rY~oJb5zbo{YCjGqlOucPq&HHdUG!E5wYBQXfsFQ zN7lCp8zSL#PN8!xmrliSqs)MA(V*a$TK|x#*5ZwC0*BPquA0?YI+VTR!!Z~Jnkpzq!m=F$Q5mm8K(W^veM+Tn$tmrz5MCWT#0BucTYbMFSx@jpAC`^5guRfQ3=ze;n9a$x)YB?Wq;9fkalKE+d&alR@#P}mz%w#y zMo@Fn-mCyle46CF=rj;oi{*ylSi-bK>}WyL^J1&nv!kd>og0-<2BkioQyjwA&-Xui-XTG(@N9yD z`>`jBdqef|{hNuTNqH@jh}m+Ol)4){#Hp+Ka4xO7K5Mr2so%6E-(ole$j8sU1~qCG zKDPK6_JOh}xk4U%vSymQ6Oa~IgJb}h%is_n3XJSV$NNYcm8PrKbAj*4BO@T1bfy+7 zQ!_T0t{SWuFxpYclE$&Kl*x4XBTR9;{hkC4rtCP!tleRlnd=(Z`RXHrhUckJ{9nmQ zTW=1G^*6#kdOSm8B)5#)RjoA59;%5>(UsfwdJ?eub!H%mVY>#jChUt8J_Sh{ctOI+ zvYB+^s%M%xK}9{IatP6#hUv(7vvdl#A>D&U$cmS~^I?bZVJB;=ll}l@MIxaz#UUxN zA30sNkTGX3K=$JJnk!^O4dw-34qn%r0}~zwpSO}(^tlp677tpneQ}=%$$C$?M!asn zO$gzAj+~0y*<9k<78h?a`Le~(8ZueWy%j`Qk8uA|DMyvfS!a!D#z&p;1=pw4R^tPY z?K!EsXGn0`cPtuuE4myyW z#^=epv|f={UxLSsKh&nyv_08E5kGEqilvNdS+Q1~3mT}@S|85p4Dji#(^IhdB+oUL zd`G@-eTP!oiQWq57S?vqdZE*jfiHAVf&5a&&iU^AxzY9tX@El~EkWN{>-Y*9w5hoTn&)lKTIHhQrlq#-jt zekDa>A_S?vltwi4BPe&bMYTqpq&OTqxFCEXseJ`;wl)mT`Sc(cUTT3dhDz;CuVoz0 zcUWsLh0HPf7Nc=9HdE>SnL~Yx)cE8dacq4mBlT2fWEGXVS*k(LY>p}MpWuho9A2H7 z&(Zou-(Kx}O`SU*NJ{|FfyIzX%4et(QZTbM22XO)P#~ZCOwkEykaA9Y>3w_XhXRU6 zRGV*5428)$=h=vA&JT`xiG^ulRn6{$e4wDM5Tin^!|Qyq8hzd8`ugA{J6aJMBAo>9 zb&{$0eCB7|6dOm6!ykl71&R{2&A`%a87+_+O51+7FRpl^OhDyl(r}sK?y2d^8NTSW zS8A7i?NAO1W?N&ioX}?s)WLsLoUvgJjkhY-igPrUh>y|+G0B%$&DIlO7Ky7(MtxoE z4vK>N`G>R!Hb_e+vgQs3%$5@ZM^z*Cb0J}oU!sqHQ{fhf6WnuDCJC!M!Jy8R%kC}~ z1ML+ehoI2yqe9%S@*cqHDg;#O)lr$7^O315s~2?eFA#odl@q14O^UoI9Ep7Vl_pBX z?@eSK9pPn}j+8;|yA0_ys?nLe*V(6$vrv_`vM_6dkskmdF;2rAx6=I8{hHXv54F!} zut*7WYic`^4>ng`>>Oor!mvU-D1t9h>xKSPAP=z_au@g%fEeepmCYhT_QrMyd9K0W z6K5!(s{+IBWS6(>sTJ-U9?5jBQPdqFxirZPN&4LgOsP?rPCqFj9rj@J+A^Rj4=@#k z6#$C6wU2d#0_MYq6{PnQ*Fd5g_dvZP(16uT*+O#*G;UU>N@FfY9zNAVQ1H3b<`Z* z6GJb5n6BtWebnfDIKXmsd#X^(BRinC`iDhL*= z)1BsLfq3Tk0o4R~29E=VN8~7@rb?5?+a9}5xWf=Bp)LiR@Dx{nOcFN;PVAUyhueLx z*rG3`HX)1HD;+5kkxp{66_$Dpxz9Q2;8NW04GO6{XOYxskGl}EVQ z4)JfA2O=}Xu3Zlt{4UaRJ1DUxl?*JZA>hsMS^H7NX`iRjt$>ptGu&tIkzZv~=N4BG4!r z9{qNkL7`Wn_Q})dnf5!(6phE%w4N`R;s2DnCk*lMBN&Rh^BrDx5V=LzTn}meyq3-q z>&rIoO!3reYNlnL_odAWS(ox$F|>{5w?nZ zVb0&tgDMDo9>T6pPv8?`;%lt2@QRmO##r({vf0Z@SL1GO3Cvpp8x;zZu2;>Jd8D6h z9;X+i(CXmDSt-I2)vQcnCnlx+hP+Hp%$I9Jn+ZJt;CX*wlf1FKd8L1$Pr~{;4N`VE ztIhiw1B6@1J(`@%*c`0iLi3T7zey8VYL^D0fjktwGs%RyTiX7`z9NXd;UgB`>_<6h z#V>YS>_q|*ohqK#dW+KR%=M-rK;lPFO4ch-?&aeR(D3cU{^R%YW3ew7k+ zmJ6A}Lo`J_=?qSp1ln%`@oCUrYiqymM^b=$dbG^);4R;8ih(VUA|?2{J78bzWaIGh z`$C~X0JAU&7xatlN%N`VEiVN!S-)eWY&Vcv1pX~e>&Ecl)dGY5cV1=~l41akFP>^?1%RZ zQdg7^npbwW%y=T~cnR}jVKbakspga!8)_go1a}Jx`RWacjiqWzGBZLN3!*zQuMF5F z!o}NuC%h9>2rJgegjsD|6#Hc?u z>qeSn?aucoyFmDi(hP+z)>ZQxKIG6JUe2Mkia04K-UZGTIfFr;C{`q z-!tvkcYX4|)BrLQ9wTsg1MXk5j5*7@+^P+l;7;qso+*!;BN6eBG)zWAvFU)rA&NPc zk}iPprA+R($np;=#NWZSwY}4uhL3;<@{g{{DuDFGQzsi#7Sb%Zi~_yLcHj}u+@s%y zP-ba&b*iQxki%4rUOYSH>mLP>mZw`NYrQIx=Uk3MjFj3Xf$Rt*#}|wEojC)o2BO^0-e~Xz)t1b5OT<*Sy)%zhE`4F2pHG18TokY#{&WC`0 zd$?NJtpG-{y4in{@EEY86f<-wX1^jHcuka;5?k2Pm$`jUMivD2LtaIbCIkzOA!x59 z4?4MNslQxEQ6p*)fxCBJfO6(wnxVWOyxZmztf;+24Ng{nqhJ9fmWpE!YAb#vuez z5%}A$2A#QFokwc-8YlF%*c~(Q_Su(m^{#Jl?d984ul5@c41Y%8^T@A|mTvaNnVY#= zeR@36l;qKR(;U^xVa}6}x>TqxCs?g7BE12GvSK3{#gON!Tp2pUOKt1JOO7b^4F07W zIR%X7Ov4b5{{;eG|4RTW(GluLAaP2Y=lv}i#&FHs5#-t1EUsTc(rc6WN5KWKun=Bk z@=gapQkdOuo{>(KJkSo*CF(+pddt6gUqf8pWMn{gNMUa}Ht@$(DF>tD9TB_d9g)poYS|m1y$I>AHSA+807@w}qkOryB8Dt1 z#;BV1`W$LJ)fui3(C+m0OBjv>R}QtI=NukTIpE|G^npUIZ9fg0LMnOU?TeUB=s~Ty zq`?h%2b8I&9xv9*!GR)s__+n!S9?gwg?^J+UnL;Jw6i=cdAB?9lslg~Ye`oekTR#2Qjuatn`u>`-^Pu5 zTpE0hUL_)=GP-4S{DW}GPlhJR`XZN)Yd5!%P-kMuWO-;*(<6fSg)SW<&z|wPU25Ry zz&77dDp5X5=pFjn{d0TLe6HFVfF&nk$>Y3Hx+1bb=ci{O(iWpf4F<2q3uDA|x|YQK z^4cnyfIFdDU;IwG!F5`=`5+p|N@S^3Z78J9Sbv>?hG{{YT#p@=Bk|g~4q3#tF&q{K z3_XIn{f2`^@s3@99@B?8J4f0I*|N1F-$5(2IbNb9h z?JlIMA@1;B9kqveO2GO1yxMb^YBBNH>yzjQvLI$hQyHKS6VG1@dQI}Z(VgU$^PlbR z+J&~~>&du0kNCq!(D_z7L?Q~^{IDwBejXbIE)dJZKE}JSz4=Ok#X2HV+Z~Ran(rHu zP$ui+Ke)CJs8Nbqk|Q_3HjSLm8~;8pp>~6vsmabd)7Ro!-wSrx7cjrd&X-*QC+h+1#2U5%)n|vZQitbz z9F?pggfeL`wKbG|unOuT$qu^U2E2+r~={hXS2%ev}Hb! z;Ho>Aj}xO7q*h>8%&7-dajaD~MUDA)sjWIPDeQ8zo@PHJ&l-!FeOeo-7FTMvFd5!v zgzY2%oyfZaQdjuHJiyN^zK$pId3v6!{5qvjsCx05HR|V)_lsbKRj}a}0{2rhX9=X1 z2#_Ht$h_-aBc|t;xCK1Ne`H>gNWd-v6)opqE;a+Ce-bjfYqPe|zvZrG_n5&iw{!zjvc%1n&EJ@UM|qo6>D6$u2v$h&D68~&w3m`C(K8@<9o%@V0OliwacWrH~fCgq)@)o zH2A$EAV`L*cRfrTWg>;Vr=zij42Bfxj19)qq+AK&xh{aA65U++2{)VBG6YmDU)t|5 z<$|_2$Ch^2Q-DT(@I{VdG~;PIVz#<=QZ3KgCbSn>hNY)du9km zf$rnAyywN_4!a*$Upf=|_9<=mT{Ai`q;MExxnC?eB5}N*cyNI6dddF*BYW$BE)m!i zSe^y`blr&-vL)B3)hUgC4z^njht)vB3DCZ;xxK%;j_3+K$*;E+XyqwRN`|2|VbGf= zujdUXO#*^+BvdAsfpl|*G1lmc;V<{4#G+qK^?P2Q(*n$F2oSQ*O|bkt-l9ddz0fa( z#$j{!tHB*Nva&S%`S!ZDPsk?r3h3gKUZmf~X~k&VakIN8^B4`Er^tB-b{S8o!iy)` zuMvec+ox;0-=UU@G!tqSn(Vzu`#noo(Y^3JF4M>I#RYqjyKPIn464EC(FKEKi*DO) zMfac4vW@i59;JuEhzbG5;n!E-=$|d>rTgsi58R}-II3wAV5{(uC7r!-;x8DER~m{nE$yDFyc=1*|jxsk|2(Zl~ zvqX)oVTXQPhsb5SndH9DT4&~{ug%uxvZv|amEPm}sxq}9M67yQ@Z9x$Kfi3jr9bCr zMOc0iOQ~iy@b@xSC49fSX`M`GfPl;8&|dHgZnRjbR1%k?HWTt_1$!+;d?Xl$jmPQU zK|Gx^sW3~i{Jp7tMdqKrUTEKuV+Dw=iqpoqk34HxtkxyDTlR^F-&>R1aCp2pAa=v3!BE7DBn+uSFy+;Mw>Q3j?< zSw=Pq7>vt)VelQ8OVK!QOq0d#Zm_?UXZlcBFAMrlPTU5D%2>Se7pk<-K-$w66^7?C zgl`;q|M_9%A|gOg2ix@}G2<}FK|SnoSr2B4qaB#d{~1LeUVk9|le!@Qqv4lSf5p?b zX~N&hnn&6WRI@j44$_a_+lRgks3yt+clSZ*#OhoD2M&D|YIHpoVUCO3-Cj}-DZ`U?1?Y|?lur5bf>f^*gS?KB~jM92@+ zFqfOlpv3uPdC8J6BU^>t$e*g3#4>_f4nvZ0lzvUh)Jz$N&v)!~3#A?)7r(C?(Fv4c zxlk|ofocm4E}ubX)LM%*u{O9N^iKI(sc%>LbuBP7~LY`O@!uYT?1=4_Sf-r{Z z>63p7zJv?3X_KCQ>u1H;7|_dkn0CLubV5F4f3M?3{8>}>^7LOvh(B-Bje5i}Qw67A znIq;Gq7M;bM4Vjj)cXu;e}^pP2y2(`bux!Ywb;Z%(){0Ff&34bL#WC4FaHe$@xLzT zlu>`?@5>n#{T-o0yFwtf{u$Q)8on7auk>b46M*Hnc@OqA-z$A|vcln57o5cA_Oc=@k~FUa-R@!e&4^YLFPP1`8!@4{iY$C}>Fe|_ZtdL4iN z5V7OIPrO5#^>;z_KQp9v1b?z1W&(jfkcEdZF8ybSmoR7${<22<&wuuRy~cTvFAsO< zdZYc%fev)}D~~_>I{LRP^@nVfKQ;W@zK+ZP8Rq{eW&H0SMc@zeI(q-K_c%2FTsbqm zf2PelUVkEj!$FkGgVy`au{HD9S7Q3&Nkl(cJeyc~AFdCE>hZ7TM_*!$wf6tx!vPV8 z64d!xDLw4|C7R?Q_UF@gk6-D@f}9})32?nLWbWOv_@$i-ElZ0=J#L7*CG&uYlVR&0 zRjX`w_)Wxz$Gn^LXL=2*pmja{Kjzop&-FiF=sx&d62B7t$La#lQs&PE>EA#-ex#Gu z1~iu?!jc`MSKjx1OaTHxNQDLspefkwevQ$2#f`o;lr(7gElk5M3%H@hISavI5JYfm zNyQ8NvUL5b2=PnU*HE%q-+KQ4#~l2T@t`a_f)b$jcdGp-a`B=f|527D7Yxhe1Id)! z>%d)>o&?MJCV@pbzSX`?2FY;KeQ&gC>wamqE^}TPz@H50wGn-Y3towT3ZtQgD%9cs z!v6m6v**|J!ifcQ6~Sfs&AWfiRsO%`s$an#n)l=PulabXkxZy-`N+nuL5_=+;zJ={rQhUl| zX4}WNz>CceXo;ULbu7|89(<|dJeSKJRsZ4`7p$B#amq6wq0&hj;5vsfKl z+o^V4zNpu5Y-_^;z0oA2=uE-3_!u-=x#rVWqvOWIMvIsXIk|I8 zR4IGI1xUX<2HRAK{v=Mha8DP!|F>uPXFNZ!L4bAyVM07^f$N3zM70>PZD-`~4MKMV zQv2=~e>ntg5AQ5m2A;l3(YOj93UY^Y+;q5JTZ+pxg?Qi{a? zTe9UpKJzQ*UsLm>?1R-spvtFj{Qb&h`CzRwIY;u`T@r`kZczxi%|WyVXl4K{JtKJ_ zKx%SuNBq?^k3aj0sn9vbC9iUGBI&-$5kptb$o*xTj_uz55R>u|uruG&goAt1h^8Tj zfmVS555KE!UpiT%HI1OCSUwHW$P3lkcDc{C8_F;M58u;<>wa)SevxjwU%zojgU=B$ zz~QMgpjD1TtMe3l4m7}fJg{0X-!K=sO+lBtm?dLY{n%S8~vL#%bPZ*(zPG@Qr zboSgosWC$zt#l_?B-3@ZNZVtEc|#rdm8})uwSg(PdRKzE^1MAkKa57(Bmwu+ zvz_ohwEmZx+W_tP{$t}y?fhZPQ&X(eZg_vG3Zi5IkK9L4y`}n_J{&2O)l zou?@};wRwG3-}#L(-%08+LK0;N|!V++3-EQSrYaQqN%w5-akH~Mdxu%Q>M=AolB2a zl$KHsp7)!q>jOG@fQ!mt6sZI!R3j?oCn!f~lYadwXSDD`0d}Ay;H2{NfA4XwG#U)e z5sPUXzAs~bN6y|Af$P1@gErL|Uy#UZGV{r0<*O#t@!FRK*B6I3of3Oa#$+TnDmN0B z!-@p-%u}OHyEm;(gaq_QzS_l&W1&MvcG|Zypf9l#fvNmhU*Z@(6{F4U_e5#KC~`DnU$LHTZdn zD!F4@(=9fBScmSt*l)Ye|MNiFWHVBwEIYca3j99#v}6YKYGnTY&DZj_x;u7q&gptv z?io;{Y?4mv(ptkX>W$M0ot;w_$PHeT8?SBnPWz_g5gAcD>7Xd8yeZ!-K|GUuiUwW9`1$7pGwLP7%R! z;kaXoxcj}l+PJBa1<)u1aAl#<3IUBZ4DX*rY1==(5VJbm)3%fXf(K+z%CMrY~M=!(etHokrFOzcx@J|AD3a~PMFBvSVA7r8+Ftg zc&5=L5u0`~?q94HGe!dWoX*Z)(@^Mjq_SVUap_Q>cRQY0t#80(3c2%5uf4LWbi&38 z#^k8e8y3>xbixZ{@08HhO}ipbWoq0nw7HksbcI)~f#<2`aQ8s0$sPG z5QV;+!aJp+=63D&B}XjJoy_8op14QOv-6lSL@NGu6!t`SF??q8L8w&uj!yWz{+erxF`lX)`YIAUV4`AN=4-Q;^UH!#U1 zvC>o|NA=>9n(XH0V$V_@EK)~Z;LR}^NFq*wM+@f7o#Bu5WJzDDm33{|#85(I`nECr zakT1Ql+zWRJmuMKBL1z5y)cl$WfUL)GXH9ILU;i5qwbHyl$Hk(mE{S1Y(6_}72&X3 z&%e1*JQW!WazW!rCO~;w@?J95Vl@6W7$C*(`WFfTf=jQ0!XQl{5&jc-JYq5(x z7GDJfM{YRfCL4H=Y*H{=A8o?3>0dE^?6o=S=sQ20OagR= zu%96XPQ1ge+ig48xsMH4>yQ5$Na)U}_5ZjY2+Hm=r``+EeQTfQquc47{j+Z^Mn9|v z(F--eCxKviJ2Yi6_H8(tgdv{#T-F0NLFJPcPN0qh0yf=K*Nc6YO_b*~=Ck@;b}BcA zK1Y2zz-!|Pf|d(0!JFNLq=uM4+4Ul{5ZUU2yZkTP;dC{g+p#R{4*PmV*g(-octd(G z>^wv#vZ3BpcXWA8_5d3?di-U#kOGk*8aA8)~4MlUI#%uJ;6PFC}+{)wB zw8r}{%WLLq9{1l7%1gDy_IK{qxE(9xG3o1%m+FjUtKai2(CjOK$SE84p{B)Bk3gPj zkzW($ALHG`{9VMC?% zsD^JJ_&RFzdbpb#Gl87kWzLQFahq2MBA-MBlbPZRhCHb;E~$MUx6_wlSan~`*AhJR z?;hW}_HP3`>|KcS35K~qw5#JiX0CV?cMHa7gA|$bb88ukZ?%e)0(Y;9IW50eKA$er zN^tLw9}?+&=FdlhuD;!``qvH17URd{gCIV z86VDIa1`4ErRMYcph8B{VIBp)|DF!FQ8Bdhxul$&{gbr4NG+odx0YJ9GX)xY80PeL#Mp{LXGBMMIiHMj0Z~bksBo`dp{sLy`qYmTTC@8iNR}R{tvo&9#aP zUkdU>w&GfusuMZbj19Zp*VF8+3M|#1PS?gem<;rnclsk`Pt`Z!Pbx=%xSxz@YJuTjO7Qd~qU4 zwY{#z|DT*OAYmHQ&IaZhYVBpdUb)qxul$($E zOuMjmZs7@7KAOyfNn8R?MeMKZWgb6MP2j~P8F7+_Wu8N)@ULlxCYXJ}V`BBAsTIGd z-v1Wf)^h5Z&kobrc@Qp=y4|;`Cs6dpU*z&(T{ePc_3c%RF`af#Y_%jS%<~<~hP6Bu z?J>!|-EHm!x-j35?<{WFB3P`~_cJewF+_^MswX#YrMp^eQ~MN!MGaQn^zgx}HcKLK zuvlXq8($$mMb+zbI5Ez)JVKrsq21j$E;0xhbzDQXE6{w7huhe9;=S171>^SJ6E6_c zf+IsDOr4bWn|&|DJ63y$xM%3?`MRZ_U(1<~gCXC&wVN zY?i@E_2{x!VczplRQY|AbH9!@vw*+dVJi0dW8W-37R1@9G75F3>3bH3L3IpTjgU0g zyQlzLkCedO*-DcJ_!f_wOW5TnDi7wk_nHlEQe}J$@6Re{Mf2PaGiE??5qvj$62A%M~?EAb?}(>yZLz-l5Ll7w3@9y})A+)^3LG`>~Xy5P(Fh%{f}K z@RgRtlTuq5k5-N{P^nCl@7o1vGb@&VNLU!{6>!CXP3 z1^WtcbvYR+(iEcJ!a6TpOlFn~l2^<@)o6{As5qV>#AIBce^0&~aDCvjpK2bC&v$^P zw{&TYClRSyD2)@NflV^ubSeJGfkWwo)V|_Vg^;!-9b>!{cut^zC{e~{^P-zfiO!|v zi!a?g;_MZ1qo(F3p31X|j}TLoZM-=(+-zkj|2>^QtU*p3`+L-sbl8lgveiOaen0Nm zcMo_t0YXxt!AV&lK@m0DnfVBxb$HyP-`(U=O&eSfwHj4b@UB*U-~})qRb>men^m>T z@w4!3>gK#gj5TpvjO2C4H* zkJu&MY_GT?m435}zD5ox`SIjCMZVdtR&4{ak$XvCt(IaNfOz$Y#Dlh-kgYFfF84ojmCuer&7qo&RTj z^+6V`Fyp&t`J{Sr2KK{gEwI!Ga;XLianlL4Rg%?#6FPclQPR27cr#7l8t4*43^B#t8dNiLUXYO z)jSQS!~4%fYMIX!+LEDO23D`$>DG&Xi{(a6V>LdtA_c=N?dh=DYmG*)+OAxj~1y+YfwOV{=wB83dnX%;c zMaTUalUGlafo6>*_7rvO^b4L=w(k69_j1b)=K1qR13M=l7p74q*lhoMS&eL;Sy7M% z5FkL70Ey-&QPzip?Gp0;eLw$kYa=kezP=fXNkzxyfp=7oQ|>+POf4Zj!}+HZXv^>Z;MEUoWN>5E~Sc(NO$?i#fB9j*{X>d zq(j$pRFFpSeGg4CBv%YY((Bqa9q)KMAgeYjuNZ==L`?imkV(AaZAIz+B)*h*e9$gx z)pZC0J3%pfnF2&qUTqIV)H0{eJ%OSPdoT#k-9gDOJqjnICGv zDb2K0CVVIFzpH$@Y=3HS<*AIu;jg`HxiRQ~M&RC>2X!RIWRW6oCjJSb`P6`DJY(VR z&cuS8a(L(#@9MX@gOM^@p1reiO8gP^Ptwm(DKrt;DvhG>XDHc?htvZN$cB2X<(>=P zwcN?Po39i|=dhENQ7n>u+Mw5o7BWvjNrUyRg%pv^ex1`Pjhie#jip}+*5NIq18mi| z^j4=JfH7Nc?<{8BUki(jWSO%yzt==-ZVYheEvt>+g;CyUIu91g|0OIsg$J5LZfdG>ZU{e41wfgMJT+L49@oG_A$f>vA$vSP< zF58J*ks|C(i%Vhej@{N2ba#YnrpU$6%iWjGP<10CvZ%Cjd_yc2+k%Xy?^KT@6rdE~ z=^btvzHf|FO+RY#!1Wf7>+2_Yd%W69*#7^q_m)vrZr$IoBGO2Aqte|SQc5F@gn&wS zcL^emq)142OLrqkNOwp{mvlXAAK{#%_kI53|BP`yyzdy#mpwM@Ywzn?Yt1$1T)#Pg zbA}P`^S!LeH)DT|A{AE)Zx8&B984;9b7*ru_t#PUXSx@k7slpoMxH06uq@y&tq7wp zMHIAHg!*Ww)ISYY_!3SjBJO`nFT{4$N|5Q+VB}g@ik8w7zI>%8Ux=SXwKk3xqVCY( zq9h7-fJ2d*GcjFJ=PFmc|2Ydo(el8$~Aur}&y#U+=8@jCrEk zX`$Z0EKT;+@j2Tl6D2Bj`#l{yJc&Y>Z^vmgaf-g7aUrPX-ntV$ za=KV){+s=Z#*ptOI2|sz*Zst1c??|*6lS&Gm|F2;G*YN4mg$%&d8985 zOWv1Qb1Nphbcx-A=JbAi0t{^wCI)VvFlQs~u+U;e=I!sp9%=EVLstRG9!U(A-nFwAcQz7dX%^=dONr*n@I_p}hCFZjHoSNK;EB6@ zj!tjzh$i1#pqxF^@BY+p(U-k*=YLn$e^YMYEjik88ngmv$m0K&K@nMeq~K*BC|Z)km!aU;v)So6J7OWEqLJ~Nm0aw)--n_5xwHILsloHBbVTPC(T~N7 zQEQKJXLpc^o$uJ)YjtKh+Gcnr8dhrcWH1WNPS%I3aO`{0S{MMNVw73!&Vn}uU3a1S zM6{DFM>hOP7>P$*h$N2E5nsX$jlP6oNs~6(U`sWN%ZX;7pLi~ma4Oy*T2{RBNJo8q z_q9puZE>4B;khWYB8+l6n%1RaTS2->uEfLaVlQi});S$||8K<$cYzN%rcgU3hEvm9wRz;1xGUU2l`IHzoF~LomT>SEjbBQmO?VhY7kQ=v*rmZ#xT= zJTO0GO;OQs1?0GnL0-jY2TVC}-BE z)LY09R46p3udH!9d6<*En{u(CPV%XAoBWNx{EPLG9);R5xk~E;9n%vVf~}dlLjF39 z;jSG`+{4w9IB|tx>yHa?$0sKyaY*&{+Y~e^ESN^OT3`^=-Zth|ScIEBA0r@ZeHXaY z`8GjBoJ^)0^vibT% z)mCt=sD`G5(g0#g!%fu2khzzo(Yj|r$n0`b{ZC9weh*l7KInp7V_`6^oi(|0lwvOA^gB{E`g;yEAunz?~h-AClu- zeLxI@W{UZ2Jz6GG@Dz*7*P_q;J{mqgO~)5I8{zW2_e<`XTOn}w+#eoEAg{kENk8zw z*;%uLbN)dTQeiPGJk?ztMLdDxjO=;|1r9eN^8K{wYXYxewgBVM;LVM(Dp(P}kZ3J? z`yS?|@y}ySl>m%SUU}-25Y^2e9D){H=ZwLEb#uXIjWuW51rPnBrN&dX}IYReccVU)%J>659s9y8w>fkmh zmCk^uZ?B7GTfWx2nQT@~fiPU2gb*hem5Q7Gsp$*JD2;8HRswX5-U}HR;tw&@Z1#;9%sLm6N7Xrs`r)XV;zC9hsDI5t;0 zZZl9^l;LGsOh?{NdAhnA!6Ff-ov`Gz&tvD~_OM0n%RPs2L*+L^2_l-M<9T?f$}H@| z4-5HSZ&mQ~rfHpGQom%fv0ZreIF74$D|^CCrcCzeFyU)@Tz>h5iT%^D?bh$hcb7<* z`vA1*xN*oDyVn^dL|BFXktmawRMju7s4!Y&64PDQ?9E;KW}WV#)BDx7ngxO>cEzDk zv);g-&o(PA^8Xew_E*35BmLF2da-e!s+Ez%vI@*M*QgW+U_kgfBI>@wCckG4qfePs z;HuDzm!m2(i9H@V+qg?8u$+!8jZh(c zQT1#`V1s_w!gc}dbvK21Ci5W#-BcC(8V^EcK9!6xWBsvLa(8~S^sCi z{0$uTJvH4?qwCWTI^KM?YUhE3U&$UyJ1ve`J^b?h&E8U1r=>nfuw5#< z8Y{YcadrR-`b?K)7OIyLV^GRObnup2h+eunmAUCjKu5QS*n}(7w(X`PW|E)VsxkWk zg!iNDZ5g;i-M3HGCJjD*6=UG3BoP@Y5Dj?n#In!r_P35e%8rw%0}16AE9==*eN_NH z_RO8zQHCaWloT}{H7WE`MM+$(ylsN#LEaW{6`EdU;97SefS{t|@XN}bSc?8#F)2?M zDs?pU4Bal|B1fuT+dIr$^5dR#Z10UZ3?MCj4pW#k=nYvBPOn~^Q0`3RAd=;-p&505 zL&Ko|vQqKLRk4>*y&0B2dGs7~_@2<$=Oy<)*--zup;2mj4=^>!kJ?TlUc!-> zn&p?r3k|TScUs-nRN~^d*3!;Hm_qqRhjdcB^^?3(Ut)<*Gcz>Y6ZuN6JIr<;h`5cd zNM^Oo_bo(KoR#^Pqf}?B*=z+f$?Ec#~++3mr(pfb#NbI;16`Y~|r&R1y; zb?!CcZbDUw0DBSZ89XR|%C0lGl3-R__fVM5mdW`M+ZCEA*22Ni zT)_x9wmPbR?nn1}Y{jq8W7&KD5~fK6?KL4s77jRAg|h0vi=!<=Z>dcTyUVsouze)5ha zG9dO!WSf{MthI9+R+P%Rr<#7OZrih|6b*|uSB2q?dBP;VYtcGjAT!&HJaUrFT}J*o zvW2rb0a-_R((>y=Rq;ha^SZ)6gGOkvCzFK7$J#IKQEem@Zw9@6 zeh(yjFp%yNOYmn(|g#m%}@)vU^3fGoWgWItj{2PO>Ha905Gmhov-w1K`;|c_gr>@*0 z6tG4Doe5fps4A1!Z8KFs9}pb3pLJDkzNEj1!y$&dybsu?OGPGGuFOq}Q2<-QOXyHN-l@(1G@ zzx-#x4kV8hGGmePFZz!AP^X!eTgDN?&)*cum5s>i=^5;7(-r|7J}c)nhQs+$>13Pf(=^bD6@S2sp9UV_`FtX z8nHF=6s;eDGD`E(QEb`f4xf(JWq7FjrZ<(ynz_FqixO9%d!9zr7IkOyOx&3ryKr5#G&H1_2@yH)~DK-$Ewc@IM1YZU5cCw}sI#gSxQsPlb1# z{2x4d*D3ja_gh)@&vSQsrtXbn2D$BLNDK>PC#bEjW5bXy?A7><{)T=1WeVzDyzU~#G`fxOtrnSd zyaEh5g84h)B!cd*MMh`1?79esb5#6Rn#Y~ZQAqg3yQ2@`;E*D{+SqfWNfk4Kob{!N zknni$dF{7^6Zxu&-8Zf4P}8&Sjf-bDJ1#8Kk4>nwxT0|S7!eD)r^H8SY{%Fo3AjBP zHnv-G7ESLuSdYH%e$I$R-h?!1hE6G>a>zX)u+} z9A&)6hQ-=eU+kG>xFUWVAxo!mec5hEC8saIOf0nCP^CJ4CPnO^Wv!sM#5qNO+7EYj zN_KMFW|Tzv>g=Rg>O@_o>Nyz%Mot;qSx-wKl7l!2%fL)YjBDm~Ci$ey$A zsXllT`FN7jzLkJ@qW8l?k=KG(N`%iYbF*?eJ6oHoBRcx^-)C;PeRS=zL0Ce@Z7(0) zo=KV8@!Gp21Q=CmiW-siX|Gvqr5y&si(YSieM)kpl%k^AL;7mEamwoQX z=}PK#OGr8m_=uO|Z<^Ih7a~h@wP!~Ofo~cSMY8QO5@LxD-~hd;sp*Q{#!}hW`)x{@ z00ua6F0OO88Evz|EK<1*L!N)|*=qW4#|Ow;I?C&ydvwI|7fj%zq9JXtTCx!fI#Ez+ z^Lg-q(j*wAIP<1|eC@eXqlQiefJuK?mHZFR-3HuL{buMXXl)Sqc1~xsfJgzfweY8T zTjydYQf{hVY(EX7S?{VG@_udunzyECH)S4l$u=D96+U58@fdG-5e{p;+(iaZ_bBP? z<0vv8cd`6Z1GoO(`anXB6j3Yn^b+}G?@IRt>(c-(qSlAtFKFoevB0&ac>9;WS@p}y9ppxFYmjrbQ|hacF@cYwB5 zf##tVtl&uEeptw!Y6i;~Vs}P*zp}b&jbqhm3p)$n0P)HIwj{eCO+j@=j%*sEwOLR%HHYgIb)^+%G)X z{j2o;u+BwNeUn@WY|%(D8-7f$skHzQEi4HVUl3UY*&UUcpAkh%TYzEab^E{4d8~K! zWQAUnahi|6E%P|1rYxh@hVGU1(cglKhv10-DZB<_#E;d+pZp^h)3^r(2+xiF;it;z z!CK1D4`A_=BX_9*u5ID72DIJO4>k;9+7obf=th(uKoeFlymyC2Z~0NYGi zv}H^Js1eOM^F~&-bF%=X#rGO(A!MoY2ND-MpKx6c=H146>;iYDKwLt1(36ZRPDYUK zQX%^luUUtR^bGMK1)}08HdzxeW#rnmjv0QqW;nWE#9)t7b@H7p&4x#w2f>+P<1;^o z;i&nUD~!}0YwU<|N<2)--F-$f`01`6r(p`G5+}&*O}vyGQ-CJkr}FA9#mFSrJ%^sy zP0@lTZ?kt<)=ZNNe>#bS!OM?xs#kNQuW4WCHT3yMuBGuZCnah&p3UbT>?&4@;dtZS z!sWc#c(K;u(;jt#4*5n6NaSsVvcvB8$XonP z!E!m$s`CS7=3(p~K?kbm>en&Zmko?uyuaDNzd;$L&*m`(dt;iByyW!r~UWM$ZPCwSZVl8z=jet`CX!F9u zx6J5$^xg(osiAw++8dNZSqfNn&h~(#uk(n1;`SfFg)HgfG_UkjIXrC$@w?l?R(Dd? z^xZzZE3wwcy081VM+THce$w}t7?@H-B?$pX0Q+Ufn#@>G41PW+}sUxn!M7LXgVGni3s)tK9Q`V&y zC6j~;1yg*eCH)5v3hAk$C>bw_nN=9)vbZe<@feX*mq(Sx=%Vjax^MH#`;oKjw~l`9 z;v>i8$ubv_HZ;$i#JYc$(xoSsc|S}0L0ulEk?8;k$qGZmFxE`sueXQO-p&&IjOezu z-1O<5Sa3+OQY!a)=*EOq)n(^MyE}qfDI_Lw{-e_VZwm%_8;y1olc2IuL1+zX1lfPZ zHb;Wa5eKVZ(aMZfhD{c3|FPz3D%YlBd>gS>_8)gMsU#G+sN-=b^A8dxOwh#Q=_3y< zWN$x(IHmxg9o+&!7V7D1E9K}GJzfuA)rgW1Y4vV2vuMq`X}KyLM4sW*zKA> zzh#{!6RPwiRYh!P&|~y6O)2C{zS2`^)Y%_>>^5&*3e|$xJ3<@N#R!nH6lbRf^-SY; zYOnZE-=b59E-PgtFC#l*1=Wh2em*o&G$1pHV}sGxOPOa(fAr!Rr^T3Rw^#O|n6yd& zn>{@mh3SGlb`{HmHuzDRc0aXRkoat2MXK!yW%Zy@=mlZZe#vi^S&8o2GSj##Y2x24 zvgs4#nqSI4KeHoWYEflP5uT3g4CkkP`A23iY4pv(;XJsx`=1XE{?c=x<(%PAC6+jn z&1)YYw-+trAgc>3Ee+Q3(N~ek6T7rL`;$U+F3e%_;ZIej)31$qE0QzK=%pbM zE5(14qvD%XzvA4!+?%I;9(C> z_D9eDGGrcH^`R;f`NXsKY_yaTq|t*Bs-hPi(SM-#=`@IgTwcA0d8_LrX-Y0X+7k>c z`YW`xA7Z|L>PIB@_^By?P^_8+aol>y;#MM`=tIHQ2OaX$YolS(F2aS%3vot4z z8>woIyvCF>>hEx&{Ig#Eb70TQJ>i6AoUpy`t3oYt1IdlL-I*gc@PS`K^WLY!gN}5f zLK&}ERFJh#fyoW~>koQaNL`~w_4%3IHP>Ve`9}2X36XN;w3PkxPJf*;{*dMWIQ7y| zfFz|hLvH3@Z*n^q>slM-x`k!b<&|9B*x^^M<5Vwf)u z#cI!Sb7pntQ_Z+@)s7M36aN@|o;oS$D%lyuj?9uKquW!_1WB%$tptKRdwgek^F~;& z7s21}+TM%$gk|1rx}600pJ&8|QVXRShMSqb5v`lcJ`#I9s=4w%U`nfWfgvB>=WmRH zd?cUi2`3g!6DN}2y-*EVVQ@fp$GG{@&Eg9=Uc=*X+b#NkiUz9oPcwpd`D8ElAJ|J;V1-vz7^fn)o>yNysh9GGOvjasT-Z*p51@fz63 zA;HGE`8iLT>-49bzO6mf02g& zK6|mWKxb7wCA^uB>&KWoyY`?$wpTvy%ih=o|AK4fTrC&B^4pI5d)(yL!Jtw?Fnf4V zE%VnY6&i*zb`ojO7)f4x)7EzLa~~0|9dnv`w@SGG<)YuZ`vvPc>3}A6$jy9QYv-Md z>kZU#w7=+-c{4Afs@MBakfrhUTI3+v4f`q~QS7H2hrGF7-8=%tI zR09@n=HpsGTm`RJefNUTX@>e{UcO@eRB7TzZ}<6bM)%uS|2Bf_x8Fp83gyyW5xbGl z>zib0Tq_i%i=s-do1ar6yUsLgt3bi|$4oQ%xxmKF$;+bceq>NQQS`$IeS@uK=pVzT zBi}hcFi~>2z)B_&{8lvR_(J-97x}2dWE#UWPTlcvAKb55)Xqa$>E%mS{E+D*#{^3C z5wZPm^L)&3y@eNQ&MD?(ZqBl(53lt^Brz-O%|Cyc(?3R1RNDw)Ph`C%`sp0kEirb| zLMG(6_io14SiqA>j#QJfI7^e+)taxB=X1m~K@RV3_XifRhJ&QW?d2J#R0#P85y;s^ zUzo#hHz3WpezyA=Zrp$7)6XXU-1&QxXWENIzscrbTVI97aw{GMbdiH8RLrzG+H!j! zmxxqeJ}jTD=QQ*wKZMQb=?6Q5H=%?rrw1Q)SNAE|EJmOKcTe1T<_!wT4q%ROxt-=& zU$8!Y_W-^tiryCit1DUff+sxD!niU2nLFw_x6>Y`Y!Y`MD14KwR-E#EESVl*vCm+Q z&FrknN5XRB_=#f@KZ?f{F9`S(N=APYj%bH)R>e2DAaS!|$|8`Md`RPQPpdA-Q?)5e zBa4X!`xp%*JB6~zJIr-GJhwR^4>@u?83K6@@SYfoPnL@ICN0e=4vivN-Cnzlkf zfC}N|X28xm5#1wE`-VlS@prlDzyu@xEi-5|8#?v$0gZ zH?Vzo6fzy*k@6Htd`n+(;+|3b;D^c6@cYPV!Su;pKe8uA$3lAaA!5<|5Ii0Dr7$WeHrC$1RsjR=+TvyGd9ToG+f|x@r`jFpr z){fhsig9jH2Y1R5oLqd`^=kP+&KUixVm&;X184sR+3&$J97CHsbWBV$mMQG9`a?R}9XS zbxH+%=8S4)>(=MCTSGI3SD@hF9DvHi0%Hg^<&qePq8Xogdfz?p;TMN31zwOpvzL)1 zT;I!eiq!q6t_U2DA9kV{O6@I^rAJ%Mu`=sHiO)!FuuW|Uy$Fp4@c>1i{P9V5-m3VS zA{E(IL*%~H%3D4|B6n}@Gy5i^1)fg~I`DzjKaghWL+R}{cW?+mOgpy1BeeXa&3nn; z;sNUT=fOMAYUPYN-X;W5E6#t9ecKsF5v+YSCbQ0LvMuYsvVY`X{1{izOZ!T_VKR$( z9B&-Ug(PP6F=1QMfpf%rtD@5#e(4!&Ef})E70HJpp&V6;)WV%u2RPF=oJj_SK@S6)Dl=nxFCe!U=SG{Vzq|Jtw#1Y%1 zq7U)Ujp;=N@2a9*6kk7wvTL25C$mMBKrrfq=O46A*|`3Xs%5s$b0uZzxW_ES7FD5-v)$FUQPJtNpi8A+wb%%aB&Aq2tEI(t@^^Nv#+bclGk=M z7?1>(oV03eMaNmvcjo5rSHXa2aETT)j+p1ysh&TA&Z`gJ1iBbcmZv|(+oM!pvf7U} ztF+&&-gs7SD?me|Ox0pR4#&M;!4%G$O4 ztB`z1I?|5>ex@qbg!nOZ^tm|Z0t>zky-wY<*xlh69g*_d$2oq9uvhK+GV!4_p=7r9t(@Asv~fH*`Fb<0_{V`kvF zd#1UePIgWPt$0H{61-TUZ#`-h79<4i%WoFO^M1Z`L{lkfy{cd0ajLG{hnH&1^oGR|I(4`)_4ej$@g;>od6Yhe^r217n+mJsL}rYcU-HXzO) z#-F~50?Xu#PVk%QlotY^htOhG_Yvyp{QXPS2fXN%0TXXzj4k|rBBu~F(AW&MEh0E~ z9(DFOlIgZ2c8~6SZrjEW;O6B~8vN#h{atOm^y*SJ?)KE_#%_3CyKe~MFK@(UHkkBc z?-LSk%rDu&BoH>|Le2M|X=sSOru}fG`SMFZ|DpC(_6={1D-$ucJb{Hm~}^niT3HoWKxTD;uSj zt}4jcD9gzX2DGl~L3hb3l8(e{PD&Lj z9N|sB<6tZ4*ljSK7HFod5S$+d+tvXjkafadC=|cUmNC0x_7`rUZr>w|Mpa^eCf$oC z+B+`zDbQq6u|(#WD`ock?O$oV)cRY*Rf5jD(nZ&8O>{gyna5GKRSN~mY&jkXY+Ri! zYrDFYUOtX^P*v5^P-TTA>TVMn$tn7)qd%8>cL;E+?AMvK>zxC=t60g+)?Vni>BL|A z&tQ7h9?hL}qiP;`1PoEX`zT*ud0{z_HA8YITmfsr@y37qPj`@+%5s0ijLmfDY3~iI zkJEf=2vIbkH@PLj^4l?WB>gjltt;gxgLER$h#(>p1UPkiopZMzhm&&~kDBSJkXko> zoFA)k5S*y62nHE}?25(>GoZIFDDWTN!GO_$4^2^a$Iku{fMjb$?~b!LyS357*_MR%sca3oq~osQhQ{gcB-wtWH^d`PF`5E;tz%xKp4 z`l3F^?;aq0xATZZ;A5{X&J;3SSTY})^pGjzBklV!`Xo+{dQ%V1Bd2!;#h$rT>c?zz zBU$uA>&KP%$I~|MQvWfk~VW|>G@c-@|f!~=AJ=UP@N>{;FQ^U5&@IV zs6A$H98qR`3k~&JqRD5Ib!~%@nFL6xB9cgT+4}1(DV#2IeXmX#Nio^KNPXCbqo3X) z#H0+Qk3l?^sE&J|QCFkAM9>7a`NqvR3IWXg@hG6JWc_^y`U905jE=<-ad>v(dUVfe zS*+&~yirX<i{&gz`sqy)y}!YT13F9F%Cmq>IEUT7KEdfHS%tYU;M3`bKEF zOfjW4%on+uTy8B$L16nCx0hF^#nO{Kf!|iT6-0NS!ch`yTk9kkA)v)#_j`e5^Dx%G z>>VyW0pLQ0^$? zE(=9oBZ9uSo}m7T@tZgdf7e60Tgo}Z;VY)oC9*0eL$W(qyw|*ZZXb$8BhzYpc7nOD zsU6>E@=MVdHwuaNK+VRn-^g_SIngQAOO3bdzSgL6%CI(o(*ZU*Di)#GLy*dZj9*im z#ZYxQWHmmVEs1>o{DJAH@s`DyO%tq}$#C1E%I1#@ys~)*$MZT^8L6nIoJ1XWmG8&_ z%fi3V=U{!*>72}Z+RXW#g06y*5z_+M{rint-bcKw05;0k#X(*jKFa`PQIBR+-3P%r z+!FhT*hEvIRt=w8`%i<5Cy)3xB6Av2CKjnzK6i$5BrIEtH)vOTpkPsQeXhSRyP!a> zN}RfoG6+~F{6F@7v}tq*+b( z!Kh5|o*u6Ml;0iqnBeLI#%DOe2$5_PIHSR46<@^WCRN2_ia#l!ypY4&?K4fK{LgTH z8bmTIW__EFChk;aTw#3%@f5woJDtasf7-RiQG{BQ3(tMkt!^VzgqI@kNYLFjBa58{ z?t~Y2^#uMYL%%95pqu(};1s+crFSVs1wWL;>@Yntg1dK*BMUX#LuFB78JfH=VP6;& zUJT=NVsT6o@b>f+ir*Co9L($^Q~35eOD&mDGKPlw?0&Eo_~WPxF1)`Qgcm*x77?2~~u%_gU}rvd?S@ zE3MINc=et+)p9cotbO& z-6%HBS>Ef9?(f+}W^{bd?-sknVuVoN?(v5TClPQH%`Uz_ceIg>B)8lX3xCFN+Eo_F zqz}Rvx~#9Vet`Il*l=ejhb}2yYk9S*2OG6IMTz2>owU>Q4rS&UFUOdry1b3l@x6^iFV5Y(W6h8P=i^gm5HL@olGly5FqAGF;X} zRO%7u{a#k+TE`xm@MS)(kQ+pwbmT7EFxg<{laTW&me$jQhC^>)s`5$uZYneVWr=P; zhMlMz!kINTnk?OKe6t>NSyJomnG0MdL#_a9`k-VHn2%DU0^)^bAT5MOwcz=uJ~e$q zL#lunI0C`Hlgr|DuGwfaN(Qxk$p(eD9WQvGqiCWe&g|_anOM0+aR>AhGfgYX^8I#n zpVU2ZgcuJ0M*W9B)GWttagP=kV|;bLG{tL26g)9}sKhn!IE(4La;KwZB)`4+&e;q0 z7D!r!TR^0$AJZG+vmZ1toNU!WVu-zbLt6 z=!sYi`mY@NEKaz0W^N3Id`07eLDP;0s=s3wOW-qIyT{4hLTS|v9hE%4$;-`&SALEc z^*BvQ=UI*UeTr&n_Dawq)>NTT+iWO*pA}L?x8EYCDPCwXj(wfkYJjbd8q}hoy5sL~ zzO8#D2wUbx8{?9q$vrq+_vy~nI#xp1gTY+F?9~Opt0sMQ*LCYO6-*YlQF~ zWhFG%GcrsU#^X*7=I5?9yj&w@hKEq1mU7U?tsEd*#R2o?Z8Y@FA6B-$W=+|-)JY+1Nw9zD5m8;Jn@Bl9OUA##^7R10^XMvAH)V%`0Sno@%D8wi|71MaZG7yRx^aF z;mleH>*}?=l6d|@O>_Sk@_|sOKn_Lg;bu*-Q#XfZjlGryHMh;Hju)f5REpJU+BMmC zY@os$s``90S6DVN3nJXb_Fu_->Nwh(mRRRVcuA_DRKT}s2L}icqlXfoY!35KCdM7Y zMMSAe?ADj5KxT$!)hT27c@;8fCp?;{op1coks&^xADj2vB`i;fXHrswcFmUXk$D31 zSa|YdEsQNi5M}fLrEHc<4Gc5Qb+Tzhv4qhYF(yCs9~FIA_Y+ZN>|RjpEnxXbi9&wd z4M_}4Tqc+BXIhAxxd>-+hpJ=Mu5$}Cy#r3t0e@ptmG63(H-6EYT-v2`f#p)lPu>hP zl;A|IN}hc_M6dnGqVi!OJ;Ts-s;d*ri`OxF(QFEOP8Xn-fE|wOHBCzG=oGXV6;i4Y zEV&@RPh_R@UjJz~$9EmxS5V;x6bVX+%H(-AY)Bv03OatHNj<3B!o(iubhud7=KEi6 z>vEyABKMuehgSzjyq^DX;qY5 zOpQCh4hK|WW{XQbZr`j*uCd~VCR+gkoPJQFX1v~Ql7vd0w4n)C5&0+Wh%t2-kfBz#^rk<8)U96e~G5A?f1G_zapt=2L$4+ z04ix8zvZck_pZ5Kkke|*B%^ zeLO!!O(qeTv+H!>Lvc<;eiRT|+oRtWMaCY4Bx?NNIO86rhlf_ZH+Z6~1z>>#vY=*mN}+ z$?Ir+0-zJ3NltQ)`dUDIyx%OR-%<4(P%vMf0eVjush7JlcO3@A32=>Sd_T$g(osR0 zWw?Of`AW0nyK4d;e^J|+Qd)AWi`VU}tu;uomd;oftdOAho~A|v_z8+^#@^1zQjyIQ z0(XK#o`EVEetBANF`vAfOFV-zJCIEEvBMWTc%q#}OLua2^^tHO z%aWa3;9)%+Cc}5#RAjaS0auhdKDSi1BnYSH3cct*I6eBZAcpf@o#melfeGo;*akP8 zfU{5?^0~HkixafJnfqd)Q?}3H{5Hl9PRPOoRE=f^K+vi0ZR(9b@KD|-4~+LSV6Q)1$iQBbdXp|B0$v!?3I z5_csf0(Ns|u~8`p04#YlDK7$+d*Tc;ae1cT0qZszi$#^;XsCRB>$^(9RP{?D1gsKQ zCh?=wsm#Ws2Rn0ZHkc|of&rUHGk5yGd!z@?T<#p?7SAQQp(;N(qQN2wHoINut>6-e z2&xG@XbFTBzYKV!UW!MMV^(T~Pt)Raef;~hSSxGG0$Z!(32k7vi`t-tt!Vpo6&T~&Cp zz8uj(b)wVo>YmK(s4Lcdn|L~_z6R`q$>^8OzeqB16sbC5zU>?QhpWDH!S{la#chC_ zx1{HCv0MilMjIbj);hr%L=W| z)3Y$CpF)eqHQx@mPM4C%ehR%RiKg&~5sDlJbF~g0!JkwH6*^6ymqsR_k&IN#SrJV* z?S5O$Xb5Y>6N=9-Vn5B-^xYYEDXSYXuvrj1a&xbCzQ_Qq(9Jx;RooUiXjGwFx53Mt z`CaLUoq)tgtsHO`x!i==6~>?}1WiW708LJWelGgQMgRHoP5Akjv7=A4FDgI@v)s$3 zWL+#dug;?Rwy>*%;zDS2&WTw#9c^uzf33pO3x%@-v;x)n!A@b6+^s3j$OWUIvaC{@rf&wF*b!u~AW% zt9e>sV~uLl*H#r@L2BG?MdsqT`6f@!tP>5*>JanHS0MvRP!6-3@G^I5mu3HIq) zHz_<4=><*uS;owRg|98WD?6NL9v5x*9O4d-H0o2*p1k}1-rG0wBH6zIQ6gWvK)4&5 z)*?D@V$37#=?o5jw8hz1O!|papAVz7gM$4AlN=`Y@&?0KGi%5vvNS@OsQ@J}{Ab`cmV7YII*Uv*PUN(9NpO!{Vr|@)(B{b#;;x zynG-iz24$KcdwTaHYqAzr%p^M=t}=n92jmxg)<;-{c;&ZCtQDl3x~`3N2T$wdy{)1 z{AHQhq@>fn0EObiVv#e|gU}R}Q(mh}f3Wr5SY zzuBXT<>kG}7qboL^DpR6ta9B1tDU6y4V1a0Kai($oY(4TEq^J>RgLSFxq!{>PvzdQ znmIpM_eJcQ&HTVWq!>16dwjZ8q}wIOW2>BSwO{aV(|KLGtOKd^$W}K1i>gAJPpd|j zSk>3#&QgYTM)t?mNom@Knw~-tLXv&9RnwPWV-=w?QMW=_ zW4810(s-yJD+T`9@POIV*f%H?p{1ku1{Z5DPCsl9jpwl73@g{458|8nlC`Mj2N~aU zgCm`*Y4kYSQn-LmCD&?HVmfa>)jE89`ev$Kl(WyQ=)lryEpJDL$7u^?n3#9!-lo|1 z^9o(%zIv6%gZ$5l#>a{_DZZS{JIrR;49DS5R630@oXw0npr} zkg9ni5x*8*RJ-P+f(9Ay<3&TFO2Z1lTJXwR6+IRQoqD#AFi}Nw2*pn9B*KR+T((D_ zBPeV_I5#OkVpFOvd9{&lS$ncyRpd}qD-^>$U#y?(NeXZjaI3k&z z`7VbG%&*(oJ@8_qk9}j5|JZb>o#3N8C+pT6HyXI{p%Cf7%O;{sY5DRWtM`L;C0Y=2AHCSOnjB8~ zmWu!N+uO&qV$RMn@E9Bf6(ZcM=|dt=7=u8QxqB5rAT3Z+@R{x{|_j1>AF zkw6NM9YL<#HnH(whM4yl#s`QYgi@bdnRQow>o5}u@Yqr;BsRfqUz44ZHvB5*D(@Vn z;jCBm`UjmE2rtfz$Y|ct=4X7O)w>GX^35<#J5l5^(8%9ZG$~ zT!{s-&%lG4or?ASONoMa&?UFLI)yH)c2!$mp+|x(D6*@-M4aYIF7ljwH6!Cr%AFx zgF@zZ|C)1HsYQ8NnIX%*ua?}&W&S#i_hycJ76LIkv zvZGYNR^jA)^`~p|$4$NHz|(~_Fc^sZ^k{BFYl1zdg+2A_Wj7D_*Axp8!pGiPd@ERB zd{MuDNMQ3y(g>E67C7G__LdHXPd3gPY6e*+lOTI}@WH>}YW*?+{))gYtGB}V7tHcs zBLeSQvw;bpt%U!t=L9%Wn7z>@)0?UAlmc6;+ne`B72V9=pYFilKKP~t*@jd9#x_LF zgc?NI7|u#{`7yfrq4;uUiMy-gl-Kb#M6iUO!+|VIY3|Z=)r>d9NI`e35TMa3A!8Ci z{WrE!Yqrp38REhNB%^y`fFU4A&j=A4^g2&?NPl3%6hT;6AyQ^Ih|ffe_Ae}sP&@*v ze~_ZNwjX4fQ15_MXKvJ^f^wjS$g&WSfhuOiUnB$W1-QoR-0rXA+#EX4Bqej8<uU2w!*9u0l ze{&oCF|JI=E?J=Xf4k&g+a-Uw0N|Y!4MbYZ{|#yRyEgXXg4ig6f5k@qWv##_h6w$S zVBr5+n16Zni&}wF_Y`_T>Y>&9$9{kevJx6jw3@E+Pwo9*W&Gz;lgdI+kan5>C%*rm zSMtEu0yWuM?NY1&DZLqRaG+j&RgwtRz7mKA@_^X0L-3Mf&oFTY4NLq zD_OTSzC!z`T%O4)aD@1G-6)Ya_i|~RcO>m2i-}}+&q?BVN zeXWeqfZbD=?kzuxQKZ>7FCw}%&1xI;bjG9MnIH;K;+zm=XY+3;J1Yzo-^?c3$OvZk1VXHknMP zPND)@794DpMk$ww7Jtv^j&(KKH0d58v0JW~RnAjWz+$|N#OE}AekNLT>kg_=qXm== zXZ~nF!epvu;Z7>|(DsR6cnG)6E+hR^$rA#1fsY4*+k+UPFI2~CPn1`#0%6rU5v#Vx;aVcWYJc@iiQlR3ijs|QReCj&2Ip1K< zpLOVUH!Ju;9mT3hGfW>YRu=d&+(|Y|6*%sX?CMmHfO)K7l>0Z7%q|7fMXEYJ|0}(; z?LKg_7Kjs24;7529AMVv^+P5}RWB8^;@F%nm3b0DVJGmWZoJyAMx$|4{dy zQB7^_+VHlbsDL6W9UCgB^j<|lr6UBSOYb1P6H!zwfCwlZk)F_7XaNK%f)s%edIY3} z5?T@;}iKMV#US!>NX*SznmO>%CWHl)hqAVSoIp!^Y*KKy_Ui(Vc@LB=0BRfO3qnx&SM{ggu)SCpc(mtnc?!CCQ>sJ14z znJ?afG(K!@+Yu!&Dd&)IeK{F$vU(Y$-Hl1cbI`2zjrN7P;Xr?Bg5HM4u8#R`$eeZt zVSp1d>2I2+wQO^!uhc_7a6?%$B(+2|px~;z^$lBk%zeLx;~BTd10QtlJsv2dJ#QCP z=0Va$T(MM-(q-K`a;JQKsqQ3+kD|j^YjkDJsdlN?lnR<8*z8V;d3r>X@Kn$i{Z*?9 z({e9o_`R0&XJc>W#y1?Lk6t}?&n&whq3D)T_VCpuCbw;H`08C~Zpz7mu{$rGN5EVj z1svo#6*oZSY|2XI<)Cf`PyU&4I>W!%7$M>{;!mg+vTl91I+fC2JO$Uuvu8SwczDU7 zKgfz0_Z$dd0x}(S#RXvwdaWEHPW?kpw}4qd#-9Mwih4sB*xp>ranItif}TrIPn6D} z&s0SR@1a?&wNg3Ry6*2kTIt?m0t6LgLbO)_GPl^OeU^ynvLCx}Xptv6)1rnc9HyUU zA7WKUaz?Ue3bO+wR1>7<?~0wyTQ``pN%9}^S$<$2#$hk#!YOXFS#0S}kZ^W3tSfL|pS{N# z(7gpg>XbiBYcG)7sq)ia%zDzQqnoQO{UUQelU9`uQE`h-=&CLD>iHsySQCpOI-W6w zx_SeKR+eVLtWa|KX16!^mIhDhpFJS495mkkB$B(|k4n128x$X7QkeLtGk?@uKRYD( z-AottYU4YTViz*KKfJ9AXSVty* z>(4W^AEyztV>FVzzlf%dnqb2z7amH!dQM7D&j;b21g{M zwrETTrkC3FN zI9-ZMwaNCq_w2OBeVd-7BzMt#?W{r0K_)>jz$ z4zB#>vb7%MrDGarM{J%}+J)AT(-`0Cg0b0N3zE67@I|imZ6o^N?79(sr zdY6w{KuT@R0ws4Q3yrnLyl4BaV}h#H&p(&TsB~B0m3)%KQ2sn)PHd7*ZvYlkBA1+b zC*!$PRifPRK2KB?o)wbmaXV1j{dq|e>t2RX_FdYy1ytU4Yp&bFX)S!=ENKYz5#H>i zESn2bsuFPH3nCXycpCb;%AIsmG-d`D6UI1lFPkZZnO%QTrxBljoLH&HRO2~QF6eRK z2v27~UK-1ri|l6PR+cexKxA{SzMUR)M3SrYwfRO-cw6iTyoqMYP}fr&VQ$m8vvi~7 ziv8L+$=(QS7uZ*hBnRD0$hmLFV;m1(TVReyuJ}t?R+Sp^omYGP(V4i8u2Gvund#2r zuyWkc<7vuollu>0`ajc(DPjq^g4~%U+=Tv04<9H5@^#EN?9hOT>QUrI%LY;BQTxcA!4WluNaa2n?Xk@)~+FR#jgbyZFzPFlS=VE%!b-+Jm{ttD($Z`S&HeRo^+{38tHOJZdj z8)sA}0L*j9r3@W7E$N=NSJ&UNMQ^(MF1d5O6%GCr{|GTVQI@b}XT%g?VGjS2K)y*_ z+8BX)_@~L4eFtBpsH^$^nXpPcWQ6pCG%1HXp;2RMel~d%+moSkl;?&LLV%Iqkz{ZI zFxQGr&zVpogT4642q`9GF2O2KQ{S>Qr1hiyo+6H|4`!bXlW#_F=;aOZ4G=K_WeS5O zaucp&uTs;5ZI*UJ;0B5~HMT{z-kA&&&R@!Z#j z^oV3b9a5`UeR^Hap?&;%ThgTxo|8UzG^RS8Xh_mm?vpy%r)Ix=$mf^HU3r1kDSI+p zXom^RGg+G%7_XbOz@P&^y{^RH#D6^?MaUbL51bF#-_{sTZ^-N()Z#4Zz4_WJMLNe2 z;Q|Mt=w2D03sILFJHxOP=T1u=^Aq!!n=KS^IFLy5XiPuFqmmg&p4^{f$*C`SdJ5hy zTEP@qh_m^CNol(q>)=ef3M1+~o6YnYH7z6|ydW+6bh!kJd8_2p<4%G)u5G_dceIz{ znY?q%gInIcOC1!XzFaK<*D-dAafjMYk@o*1&>|o8eAO?lT9b?3S?Wp3=T(mPdShI= zS&`NAF``$HL%pj^aJ*7V_wv`asY5YhxXGa^Pm=MzGj-dmte%UMCuB;5jk;D`&w1of zJLs2C#h$iSZ99tt*~fJs3u>TC>E-$dTyZ(~Q!kX+jyujUFir^jpT^b4RJVp1TB@0%7#BD&{q^x9l4p#Zr{ z5e`Y_b<%Y3p9Re-+^NatjH=W&iCG3Ew@$nl(g|f%RaDZB6Uao5CeDSH6jxUVC&M zUhsG{Bq#Z9iM0qSo09wbf(A!7k$)cK~VCCu`29Qv%X)(g7;Yc zW{1b2Z}K5e`Bvl@ZQ4tEQ)-?Z4l+Dq>Lc4j>;|lhHy^(vU>89}g?x1ogW9Z{XnS)N zSU%R#&c>{Bl>Uy1+%Wrrij4!#ZjXxsX*S_MG$Mihl z9QnFgmK1KM+B*WPacU}n&R;0gmlt`b2#~01Eaehyq(T(uOc@SVrJIM#xvoxb#_Ge>qj76}z6hHwe8WDnFTR-8vOS+FP3gUous-xM$E)n~ zs}E^0m(*A^3h)Ed*>5B&%!EAiOxh=7V@3C?9Vz0KqVNl2|4IXTf*&t#vT*)$H!F4K z-o=kTH9&phHU7UbzO=FTF>NspRu3Q2(1q*|VPkEJJX`(bNT435i>7SdC=0C8@+xoh zUon@M51xUancU-*QUF9r5!M~1<=3C-mso$9P;`$Gu-HFCdS5NzFW@hTx{7cyC{_L`~ z)@B9qow%J5R1ewo#PMb6cz)!fGSPGsNo>SmL;j-G!d+BN88Y*rc7D*YYq=p z;0=t-jaQHI633P>!*5&g6y)g1$zxCC!!{c&Y9e#G${Z{m>;=OTjBV+Q{T)>1N~BRFgVzjCTl1W zAl3zNy{EfbgT@MGnh%#?PRX9ySO^Us^7>Xdil|W0fbi;^Yv^o-7Ad>%>D$uqXoRJh z>q&VW9`c-stz2SB7i%-Jn%kSnP zOj>Pr1hlFBa}=86MPb`k;7nN%Mq;L-aF3g{a?S}RPEXOtroDql4~dOqm6PY!WU@5r7jGhOQgC*Xp~AZjXkd!_(zmvd=C2mfHD zLY2UP3(I?){W;dV0OKSmFMF=#ci!Q@{!4KE(ffPPkp6C_TSGYf2>~jZZj+#g?f-V$ zVxiFl0V_fU);=@-RHW6o#UhZ{9xZC7A0)@wM~s<7 zcpNGwZhMiHun>4YqIaZOfnSU^yiY>oLS|ZL+tyru?rEO!VWsW;Wh0@7Myx?(5*&ln}x63M^Vaa;SLDL z5ndkc=89$(a@;u85l?;=n0Y>>lSeb66`o=)!>(Wm2t$sM(<>`LnYJme4~2ELG)3B1!BN;0A(YlIUAh5Ryk3xO$mGW-`Or>akp z`pRXN!5+Mf%oP!jPuJq)-pgiBaF|dOzOm6Q=b#zIkQ$ zZoCu|#8;NLC3TW_k}YaNIk{hsnM2ZKilv5P4%~QhOzX7Z5R~WepQ|zeh)3sy*cp%h z_;K(JAWjn03cM=%;*Tlu>rEcaeGhhSiFPm##8JSY_igVsX>+;ZN9B%VN|>I1wGF>zmrqvjO3Q|*a!t` z(wr}6pWe8OU7s^ucP#6+cN{0KPrb!tI}kNrKzQYPCnKhw@$W2p?{^q~pFu4c`tvCx zbfHS8ZtMZ&w%WaqFe^#&jIWG#;VbOP7pGvgev?m%y_{_7aJ}lI5O}M0r*{{oM(dhT z)?inrg5{P@PEufag2-tpl!x0au0(q>OB^mgR^@KUELmetpD+T;Gk61^jh!I4kH6tu z$G*JeH5^Bj)lr`JP8WN7Hdp@x?a}-#qPOFKuL{Big&+m>q%jLBu{7t(x)q9Y%4Yv9 z4)4ZRn4u3qaa}@jWiW#}v^Sd+mO!B^$#fXY#QW9Z;r3eP50U#O9TL?Z-_pJ$xWE(# z9T2D;L9-PPCYOs=s7Ch!;cY&~TfOXw9;es^ul$8 zk4o~p$UpuElt&*c>!Wix?Y2XRi^TkYrxZ5^KuB+C4&&mA^+^6JnaHKVy~k`i6CH^3 zECZ&1)zGRewu%;UIDwFe!t7|`)M$?!!!M!KoJ{Se`Z-aJaYA*x##J6vJQQJe=;YNe z!+R7Sy?Sx70~MtqJH8+m{3(b`W4H3!%B!gz)Er(3(E0u=5SWolW{+iFJWAMlUDE+~ zJ82CZgOOX+C03L|svXqMGepiVOzz*c*Zk(!r1OVFmR>;G63)X#39QFY-xv2CZkVOy4ekJ_v3mGq)5dyP;S6VH1fMz89Kz?ua!^*a(>?ykK( zsJ%!VW!91)!deSX^WDO{i}YJCBVtlm={Yp7%zH;yHqcyC8*Xwyd#n+zSOxHh`Ffau zZ6F)fE@C@4(Ty`Fo2dDk+A@?b-qbF&ou`jS{cff;v+~D%(9obDlM& z6BWG^#AL;!F*9v(U&wb+pn7$3&Mp=5=xhSkiL2*jLMb6TC{9k3u zCEW6Z*eNeUAvjH<@-Z#D`^kW2fWJcJ(^Fq9kcd$&U#Zx_0nF>vd z@JyFoueCi0RwI;1;NZHq*2bR-Ika>dV@In~*xv{z83t|i(^_VFcK$to>UFqsr5zt2 zeFg(I7w=h=U3f7|d;zsfWvXEX($Y~qV$MW7y4E2??ekq?UR4)qz*#J{wSS6t_;f8` zF>MFhy6|KQ(kms4=aqY&@>BM_=TD~v$7^LhlhMG$pnYr}O4GFs8}HvfFXvoFx=?DH z2IQ{8#NYMgdoQWI6I}3Yq_v%y8~jA)ZVkQo$gdwzP!m89TtC(HJsDDs#3JpCL zkT;{(g{!?5`*{nzO0P$D-Zpbq#kU-7q^Wv*nSC@<*|H8nGq={ICmDZcJ5k6XUfJNZ z%2iM#um%%r4br}LDKvgg9#(byA@k z0XVjf7}wqaoLH!qG1Zv_KvTtRE@l*4FWQ~r7`QPihBYe7d?M=1VODX_L3HQdL-yw{ zyX{0``M;e6xQ~zpH^Nz4pjW3;Sg*Io3J-inos?>s-m(NJyyw-fp`Cd!pF7AuLxC51V|Imc2wh7Mb$V9#^u6LCxPH_V`|fwnA+^~o4g1d!$?Iva z&)uF7-NvHeJh}}e`ShIKaeSD`P7wg4XMPRZ69YDoD@Oe7`Cn%jwu#e#i(!#KP#~W-8ozRVlFFPA@x??wY^j(K_P5->gYsTxU9~6%Eq0!Opz4C}wFyl#?n{=#}_S~5=!(hB?}CD$Xv1*T{C9oV%qN~)PIvTrCv6&eRs zia}1K(3un{Ygm>7IkkbuQkAw~@CW21+y~na`aT_p))St&k%ngtPppe`m$M)Tp&q#K zF7i!;*cRgxs+g#D&p)EBtOjA8P>0d2FloZi|f^$7! z7axUL&jPQR=fuZL8EOei%tF?oD}=6;9qp4>w=;|?-R|PtAfhi;6jZ;{+uKeMR~bKo zx7F>p>Oh~T8&CP ziTsUo@%EhmT&AE{W+kpt(L&nF zWd72ctkXqfZ-6>sUcTmQK2@EdbnBm3LI)MTc8{NhX(Nh$u+HZ~Wr_|0gaugtRQI(W z!_{2UKEGep7BjYsbm*#V}WS%ItlODbt*ayw{+kL)}3yx0(Rb@I$!7C;+77G0~= zw_Vke?5B$qBJCCm(+=K_pD%!mm60~i=as+|@=IaL@hj{O-}+nM?33Z-3O8gVQ6^(w zpqu1Dk9xSU;qZ9|=KYTh|3x`#_(1;L4#Q8SVX*)82lC&LD@hXP|1C=OU&z%#g?b&s z#2P}ZS4zd~hz8IQc>+NZNx}*C4Q40}AM-n%qUx_ueT+n5jK4sN1T%n8@Q-YMzb;k$ z82_$TMyL@Atm;Lv>Ce$Ubn?1BXDrwjzb=_jxp40+n{qko+{*;!ntx6#PwoGJaQlBp z)^Sh zYQMor0h>O%tOYwkp9K}$uzB?*^s6H&{$+W`KjC^qZQ|kb%{OaUy14!r`FcI7>b^~Y z{wI`ii|Q3%L=(+{5#}dk^&h|6b&lFo$y)zHz%EeazeTfSZ0CZVOrSOD;CyM5+6j{g z8?Ha5(bpH?1#8+D3nUqT|LJqG;3}Ts5{fMTxVWF7DZ>GVpMvhKc|ylssV}Q+Qx;B6 zCzPnaaX>Yg>f`<)>kjsnSAQ(On-TQw!!)OX{5qk|8pzh)o}2&ub{>465ZX~?zot&iyqPsaHh-&wNfpt^b!&`&d4J z{6a`h15_Kq&nfXAzN?qv(zKu~pGtAVx;w>48BbrFNvhm_TPsm}6S1>-q0KeClN80R z*U|EVXLQdccC{}QwrZ=gTJdAY7Axeic8x!?0RBg-T-%$Xr$TVS`xzQ5_iHBAX!yz` z2mf(l5BR9hQp(U(lb8P;c2!B4RTlH_{EgjkG7Iz@JQ5V{LklUwt z88$Oc2Dg3&*_u~_Z;5<|zG)P=R#|x&Dm&((7m`%^G)Du#)Yxyq_47li&urry*h(*m za{rQ`JyQo;(tDDnDUk~k#6DzU|5`OJG zfu5G$rKBtc%Zpm?bV3u0Ct0t^d<}fu`r|G4g(7A4=PbTYl||!}A}W85hy27*u-1KQ znWPl|c*y^DK_1|zzL^8N$K@`g5iJD2#E}fkBdAZL=$6_I=W`6q7}E#DU!(%~g#T;v z@*fxbn@eiCKwsw{cwzp$Y3j!?eEq(j>;Hebp5-5WH;nJ0I@3B#OF$u^^4jzFA*-i4 z;>bCl41V6Sd;{1A;_lZSk@_EaI1b$ZKF;^373QYH3GmXsUHogUeqT1);B6%*qW{Yj zb*ln=9^(?i%;x6@{xOtX_akW8Wc-Y-7}Ub98b9pIwM+BY3AUil71s;PGcmj{;dOS9 z;$S%c5CfSOwwqj(h*SdP%-f)FE%s9yA1j!7%IWj1RUnS+I93B04jM@X%^VCI z8)}a#u3VL++}#*=?hb6}iH zEM(`d7(n3uq8j=KYrMNe&#T4vZL&ory7CH zT`#KFb;=YJ&y?=?jX$)1$&w4e#;|T1784%BYZeKJ)trX$e>EWBZJahtK=MXtH%IOG zddMZ^sD|plOsCBDSU!9+W|Y?k=}Ffus5s&z<5c{{8H4SA0|G#tX2os|_GEcG-~e3* z5TCNoh|MYu=y?q+2e%lBpY(~Mxqp#GTAAq2jP>xpeVAi9Un;{)g?{K-YlB4ZP-+Xv z)iAi$8ciz^q;>j2u3UfD3q6+{#ipAm#I@SJOfOXzND&{h%x&4I>+{HWzuP}kVU3*K z-7C9&*P;b!lOhT{-#n%iyDNsZZTSnaBea>h`lOgq8y=;6qm{T~{qfdiG!VII-e0bE zHd7L62A6U04jrq2F3`;!sLKsFasx1QX_*}c!}D=MA}(XCu)~|_)Toy8DsSgO9E2C< zGc)JxoM6Vtm_G=r$79(Sq=|rm*DbS$L!=2)!^m<7T+9tdPfZlA{@t`5IRa57*l?sdi)X4P)>JAD-utD-4soIpg1X!_{wmHt~m>zq?NkYgXVJlZ(}&Oz{H=Qi4`TLgN>Vt40_1XhGI481Mk z}6!`xSi-{%O=AEY2cVa~6o}Ji|x-ofqK;{lA~H zGzdlaR&ooNI{@y03bGGXwQ7=VDzUZKJer~6X_{WZKlw0o=?;MMwR4L+^CVV$sVsXI zJ1*P=)O+hn$x2{uq#yHk0+CFe@nXNP)CWYcwILDa=YG|0vDDgax}at3-`8$jTzlJM z3an|ESw(USylHAO(r!lN{Fk52?CD>Ih=X|s{d^S&gPOk2izDDDPxPTM1>P(1%CE0K ztx5CVfB4I%s4OJy4KM77HfEbB<=Z1 zv9N?Bv-j!aU&MH@t~F=5i%iv}epo>^HY**_sX9VOEc8RGi}*upM*Z%63^{;eQfqM# z%ESVR+qaxM78O(5gpC!jrvurQKQif&5_aXOv6(z$X28m$XE3db>=T|rqZ~pulaikC zwVE7m#Jmb_uBs)E!ZHQO$Zf%ru7Gf|3|BF zKqt8IW;o0%Nr|vhyJcSK_N_G^I3la}ol&zX5POJk%*^A_FOF@FU>$EZd-zx_p)Pm2 zgC%EX-WdP&Q4S=) z``e-BIb7f??ujjh=@!@^p!~jxz}Gm-CiJ%IsVE0fFtGrqCePh9UHvr+H<4KJq5PnYJA<@> zOotmyGmD3!0!rAE-nUMe#m~o!KcHGIG3PmT`0MjrPnY@Uhas&ovE5vkFEkngU?l0KE z_qx9CU%l~~&j9kufyHDBHBL_QbG)-RSzz;Q0k5&2LA$o05N}_FGe#os$kjBkg(#ge z-~E&~NSe{^t3WI4vV;ryk`v3FvB~WNhqfwDR{`;R)y5dqgG3d-pGyY~=ra(^6a$b; z!<~k^C;u42R|jsa7W`_bD#WO`11ly@``>GEfPd-0AUP^t*vSg#yp%Y{qqTjB{g=z( zrSm+ukq>sAk4Jk5B65X0xE1A4tCR73YSBJ?+Sr>lbcCt+rdmQ-Ib!jEub<@gDVyY8 zm%5}c4h6N2`y{HxpT<6z2F8>{u8e~^epR}82JmF$qs9EZggVGj>Cru+$IX`w(Ux3qC`Z2$p6{FFb*6H zFEdfXY2RI=T#x~y}y8K{0}j00IkXgaX;qg750cKzBtkU zapkP%Tu;UUrZX083{moy8)anX(Cw}EDZlkE3*)9{a&LJ})n+?j7F)f$0X%vfPBLz{>d2ngGC11dw3~-6n!a)5n0W%y zz}lW>?tY)ut|KN4q3iH;#a`C9E?q9s5FR)$s)>=rpM81oUrY$Pnk6-5F4~ubRE9i` zPHzs~U!2D9^dYj?>mBv;-*Y4ES(>~weg+T>=Si%fJ*iYUC64m@!AYwQ9A(91V zvS+2QEiLCUYSm&SqBZ$fLRYLZqU=P4-d_f=%A^#MDPc+IH>b(!c@3hC@&yN$6^ zQp;$V(Rnp{CW9-23tWs0)c8878@5ATs#}_ua4#y<2PDEtRDtTSD_@!J@bfP5_#`>{ zoggI*JhX9hVXj%nQaFa0>>9@tkvWuBDGhn*Q8W3QXF)CV*td<7rn*r*8gP8+Cj-F0 zCiCekxIZ*Pd9%CAkZS^G!a1-E2B&*N_|;DJa#Ee%e>fIikAeKNZ(`F6s3+u^GP_%w zx6rFLPpNr|N&h`h@gKs^iJ|rEyrF{74>l~q;^tQG>>==M>kfOE7FqwiM)HV5gGavL@Ji#oX6jSd7hW~Q8 zJqx-%+dn)Df|!ez%eGd^QQX_nw^G` zzt&$v^v<+K8aF zeTORXKb6Td!@!0`+9~l)8P|dYl873+V#eUNm~L!cfkc{wT)d`rqayvRT9vTfb5Jp9 zrHAgjX4g}l&9y82066=J>)r8PmwJwV@h@PvNjw*2dCdBC+_&nTr=4T)#WK0}v*@)6 z30w*j%wP>=P@SiQhXJEG?Dc4Z>gm%7rIvHFGk4vEYzQ7Pm$fddvVw$*ug1Y8Z+E&u zB;4FY862itk$q=0Wn}YVAaDm}LXHry9SL3xICN1|wD9d?HgyND#0y-=t8Xkocu61a=IMx0d$O=;%)s1T2xjot%n&Ho~5Zf2Cya456fGhDcHmdGgOi`tRS;>*LX>9^)edbjNUGP zLS~VG02RC}G=7AyGFJ-$no3H{rQ;04+?Ct?zYGu5vimz&m&xt$tJ9-UNp)z~e?n>G z&oGGx0NHE5L$=$L@-XDInA6Zi^oIG;VJ2SPkDF|RY5_E7I%-8-1~X4w8Ll2RFSCz{ zkux<3-1w4Zzo8I_#7{rqpQM!XWKc5#=W9n9GDlbVSC9hOft;u0jSju`_4+*$Y{uJX z9>_}{aNL-Ckjx@966CJ>D46@e`sa#BLDZ@Fw^y^~oTQXCb~E+~rK+s4QrZ$EUYO)* z>ls@IIntaU*2#!&Ga$OAk#oa{LeiKEr8r(E`Zc=X)MF&%1HZr(mz^clK9O?zAE~+wV#) zZO3=gagKyQ^(;vdSky}8PBuX?1q#CSUXJ>LFG&dqDjWLdU)WGFP;3EH#4k2<*A6uX zsm|s5CzGmGFLTk_nBw|~Zc_|)hWJ+LFSq(EgeUGg+7TAS4f zftzkt>vuPcY3b;C3?E_oLA)`lQrq7%AVV!gqsnt$BaePCTP;DZHOHZj+Gz(R(?J)xH)cKBb(eeDqzsImzEet;(Mo`K5XDG!&thGXPPAu%joC* zH9!@#aQWbk=FSd7Ks@;UEAfy(MN57o9vzd%Xs4&wcF38suDxrUMnN}^#^#VdvT`gcy;-7!kq)QK(-Vq$SGH)iCvWS$DC zURd|oNv`G2C*tO6Po1PXZ!Nrm^VVW!Iu8KO$bSW#)xfqn_8Z__4+TqS3pZFO^zQ+N zTYGm~jQQ$Sd*QS`JlrQ-2nCJ+V=lL*Ha8tf7qw|gZ*UcwSc=dX-)&V2@T+(RCOh78o@m(@3&&96T+t^gkceFc6 z*)=}F^-WKmhzxgSrlIlaJUU;rf?1S*#QSExe!)hkLh;1J`FB~fVeFO06lV}b( zrzYQJbk-!`_NAq;4Wh$Fu_8;YN9uE#SQW6HxOR$&A+5W*&%+<4`g&XNE}x>f9XZ~K z8@XQgJm!Ghxtx6jT2(mYy!H!3<$|Q4iJz+isk}Bl%{CNIoQEh>cM~RF#WT)l5QDZMK`BBzr zS*jF&Y*g=!dRdc_moUBFO?Zk7F!@o%x0VZ?)Gs47A}{3A5$E)2eg_k3s2PL_@wva! zNjC~WU%DgnA5|gGg3(;G^d`Aeh76n_FrCWsPSc8a6HU+UI~O#f&wYY2U2z$!$sn*-*@J^~ z{V0_-!XB;jot4z;HUm2heKjiT+v5YtyYr>idz;s?k-N-}l_h%H4R1cxiGP>&!W1;q zk@Y|zX}^G-;(2wYT9oco?(uPjL0qmu=CwmJgD!G}&Kp*$F+-J6z+-u-3tlkLmFbt3 zGcoIzRO@jYg$e4VGpahoRKD|VPatJt(`GW8KHi_B-|L!5g> z!rr=!bT3LlFKJ_i&88(d@<*$39wMuUP^S$IP^Vj33MIc~GpPvstZa9?GutM$*O~S9 zbE@~(7jH?rZ%(Ni+7Z zN}5bC2V8zr(tNE0ZwWHd@jr<{&g~8cC^YZv+{^-BN3=ki0m3f4<}P{ZbjZ?>s`RSILVhY9rd9KoVHwS(`7AD zs@oBdN{6Pq^yj1N(KN%8_WDjZ^;7KDSE(f}>n`o!LhSN2!UPlTi96LG3<+*~FbTQ+ zblTuUwVAHxP4|6r1_mi*ICD%jW&Sa7>8TY{;KZO!vd&42kqcR9Y^D&pO}IP7yGw;Ifau!w5sd`w9a3QRENgn3-j zmNczwg0bkg!#M2nyQDm{Mt67@7u-i)?zlbP-Y+%go<~o@)?MC7 zr|%^2#7Pynho8MTm}!3`%x*+A^R;E_*r>-+n^pDhtelT?elfEcZBU3`a2G8=1@@QC z=PyO1RHwclMceBVduXq+i>hL)3bTS+TS!it&!p`{GLmK>^2Qj(UVja+byWTDmBL5w z0!n(T=0v&j`)UobU7zxeB`fBicb@5_9OP7#r24#w?sS z!P=4%<<$9l)2-AJB8y3fZR7LW z_nK>65#4RkpS5*w6phs>34ekFM~*DJ&@X6Pzzr5r31Vm0M&+1b}j(ovU_7|nfpo!gwR3ei2058U!utVAeMQk?!u4k`In>2|6qlD^x(oUR5PvR zC7PN*AK>}vbrULkd<|wQC$3;>dBpW-Xky*HqAhx#_WTKPZ-R$a2TOVJV4fiq+smBd z05+9H`-pI4Jii60JP(p@^wHi9$lTGfhgn6HF)o-n$IckuEPI^-*wU!v9EF5)FLwtD zHrKO-ZbbF49k&cocFEa*R3PNf^0|#<(Lp<%>JjMP`(o}HvByyha8Sy%3tzK4rh2Gd?;4aynEJ+U?4Q?8O}gREcOcX>qxdE z;@Cx-7g@Zr5}{dM+~><;M))+x^grV!t*^LV@Fx}MbWxlD4G2(ER!USH+9p8ON zM&Ik%&!Ac}6-Qn!8%JFLF-eP{3z{V;)$JVUOJ*`Sh=zK7BPUs^#pnuQkrQQ)(`awJ z@&9^SCh<~>F_Jfjskk6AE4Da8-CJ)yBxSp<2{*TmhmR*L&O~6#A)Ug^ql8Vv$>=1E z?T6qz4i~ul;1JC4t5!sd5X0}41Vd;TfHViP1%A~R2c$vi80>Am@E^o(#|j@DJem(0 zp-y8zEHuniljN0mcJC4L+**NArM;e=YP|66^x>_U6sQMbLBhCd{pspV7u+A`X?pr{ z@jhn*$Y9XsR7g*j#tiyIgjs3=1SB~v#bW3_4F0I*n<;*j06?IjJZ|fb?E=g zCP0ch|H3(2W2*yW$|#FO`$5YAzacYIV4_vak+k5=$tGX|zz^al**6AEXILXf^SNU< z`$D-NpUpcyw=~7AI$*m%H`SS_fH?x6bq?(s-W|9jOEa<0(jk|ZFeNcBY{7jygAjOtLv!xUsy6# zWmwP7%=%p|{NGr>;E=2LH(I-3tlJN_*0K3-t|XjW@0ub3+#=ZLBtH{Zd(BF`YD{ZN z?!9-LYKPIUn$|?znvRvhb+yx2MDTML5_n!MW-aMb_k>EPgCw!4lku>~>6D4eUVGGo zRRP*NN(e7i(w@K_0kTPR3sTQ|B$G2RP?sWt-q2`OSkY$NTI;Jzowom4NXjSA- zfeB+KPCduv@805AE|^k#{YwK*{Q;i;B0KlO>OtY@v9Q6{2C5EYCIQX5M}bt?SMa&z zwLzgOCo;JsO5(-qmcrLgT!C5hCS4{JU=y)chYwj9g~)qz);U7_NAgXB>Qci!SM~oZ z62ApMJmkLpyx$OV`mH`S692~%GeWSt5QA%Xd>&0UeW8uTmRu{jc|+=IH_cx2$E_@z z&tXK14<;EJ7n#mnz-<^DqW3d7U2G9&0Mjch)w`m9_>cASx1{(0NS*lme&ic~1~-ns zE2iMrK>k|>SH7NapK4jtGkCaN7vI|?QhU_-$Kff}W^!3-ajG9OO5hmxeO5!{McQ>T zDdD>Vp?Rt9A)?OkeOU{k$+`F`=&O~e$>(mYe!qVJ7X=WB%_%Z2zh=z@)#PtvzXoh@ zzlP-Bepk3p^{>^pm;&%Z+DDS`o<8pNSMi;3)m^8L&ywg5e7jM68`PRow*Oqg`MV-n zem6J@iMe_Y_dkZl{p8aBCe(Ka50#9mFPp}#j*;*qXRVNgB-S8_Y@k+J8}eH^0gEii z_LDoYkk8xi6n3&U>yTJMRnm^uXn9*4ciONl)FH8W&Ebl8VaKGCCy%z_hkcxQAL%`R zXgh)jsBB>vi~G-q8(a_6{LDT!|0BWju~*a;wtoU_urIg!z}Pxpr~iGqd`tn0XrpAN zvsP0F~gTJ->>gjn0&G2 z?HH+>epa2YB)*6kWdsP zlm-C_0YM4L0cq(j=@u1GX{8Ym>7lzrknS9MP^7zI2AI3YFQA^|Ilue4_xBgWJMX-) z_u6~a^Q@)D@4cX2R5VZgNjS0b8Sd{;f6u4r=o}IGhm+TRfqq>p@docdhUH|nP{(6k zQRRdgYCqByrDluY53hAVKe074pduu_yMJ|udD8fdd}W^ELY9_*f?RR3L^2Y9sKa zLEvg*W-e$Ojg=_$;|GP7>9;TDlsI-w3X)scVcY-T^Goe{JOf)QXl4R!5K49z7py{1 zlmyiCcL>;Q`FP##T6HAsdeA*|+PK5UVWjj^QZ-L}i{ox3A0b;7d`*Sy#3rS-UBL9{=^hJ){3=w*Y&I2cUq= z5u{8|xq!b^Gc|XQMFBnM)M(zu`Q@Qpo8v1{)1sqPpX;9Co9QQd&iV2{wn5a!WA8{tb)kC zB(s?Er=DrQUDQz-K%E`qwKn->v+^-6{C(7^F$^Z6A03DfE&?I)Cx%kMlshO{8p!U_ssH+z;IY8ee zP4i37GN19*JE8of54O|uRGKP`w7zY57{R01Xc;q(_)SP)|dn!(R+)$;)IT}d97+3%E$PwH znxht8+ebEk#C^?9<<`c9vO8f<2IkVkzq=CrGpTDHMb?MkDt=j>zzhLGGnJb|e>`M0 z3*aRxpR~OE_00eAlP7v1cFC};ZpQ_k2|lzXQ;0RmteDH&?G3BQBf$vP)YiLneBD!? zr_d^X0<&rRWVi{y&7HC8Sx(M5(H8$Ix<@>$kA>B)^qx&6Ja2bism{f3s!UGnTkjHM z1Y5spPyZ$6`$|A4;FNgeCq#w{bmNWmk4*o8CWkdzS<{`+*q=DpIzL((LsmIBu}q?O z4*gu7x6j?xEKg>r8wcS(hk`0pbjy2M^N>kGi5Xy2Z&^3-ZlxjphLtiSWd(d!glbID z!zb1(Oo@F~9@O3n$Sz!+;3BAQtM-=87?VH8X0VYh?WE1!9`>XsGTp;bJ1OE0Yq~p~ zzEmu)!H28Pae zR_msAI3P6`cYmK6uF_2b-4PPdg$LA!*q|iW5=TpIc*5SUtpLc(R{j1%#33?fxX9cm zPruV7Q%#lAL=iH?mh@SpGs3lWn!NRgOU&L<2FM5xG+v?iwKXva45&1{}x>r<%0Q zd0k~a)T^_gUcU2d7zF7LhSq_<8am?C&8b=HB;tjz?S(9?^am>4W>HRV(@tKzXRk=h zLfUVqm6sSbQ1)tBCX5NH-BIPfVKCP;#NIKJY5^sohuZg>c#%He*f#gq%oR=FSsqC9 zCE3(ldq0oR3!-ek)V3}h6$UD{Q>NQYhLMemGOaZ0I$aTphB*F2kgM76#0y=KpbHsqcuWVBc@GLedR5Z{@$F zXH?G2MM~8-=}T72;xk^GbM}v80U28v1y7&#bf=AQ_43+LL1bGmTj&jq?B41axv`1! z=oA2j`(jV&D-DYE3D3Ai=!bxyAK~f5^{Mhd;2x;V^LWuF@Tx8-tNBQQtQU6R+~SZ8 zVsWF?o=74;&{|hK^~q9HmRjBlEE6ZU4)n)<%^J;VZsz7-U+$coK$g5WUhiwbXxx+Y zEf&kS8|+Y;mr_~3-!Vt-y?IG>CzB4~)yoYU6w?6nAqKuUl5W@-m=_H+iK(-LN3B$Sd@(ZBT++421*&ArxT`Fzn477rnKhH0VpbFj7j8SFa zgc`b!Zbs)3gIWG}gUM6$_Nr*Ts=Zyq`A)%f?#!-Epm!CEHAS}O`ZeyTadn5?fu}pQ zc0u*eAa>+Ggp+y6&6`8^Rr74U+V-!%!t|c=UH)<@nPZZ;4W<4No8NtRw%RI73gb>5t}6qIqb^aD}q`JctdT@yhG51_pud@5B@=AU8Nc75vJHotC9 z)Qt6Nl*2YhSke@hr5xE4Xfo|*d`WC^xKf#!%fzBM+MT__8Z^M}%(`nFD|ny>Z3$&u zntgs)WDa|{Ai_1DyRN_0-1s48X%yH@mS?4I)tkkLpu{p}yOoKk+;568la=XtqAe+j zfr_bt{Rs8msspjQ@VkmxQjrB&E1$3wPCi=p-V?&ZWGy z+kinmN+Nuk?X)7HXr@w01hM^6+RdF&-Qsd2%rIKGPuqDGJ`bmJpS4bsbTBP7HP!PX zgRKZ=Lk_4E-rh%@8>P^dp0JwRF}#6yzbKzU(w+FZaJ09QEgw8LAlp4*1k?`lUjem) z1Q9epmp2|iXlW|+#cwF|hRP4fyE9uO`1|e>9*1sp9mO(UP50<#ynZcwIdr%S!{;Qd zNPQYug;GL3`(#=)$F%^OQ%>gn*AKxbp@|EN;~NQNRfBEgB{WwZj{@2G!g{t^Q>iRG zuCvtr*;LoYtPHD7i5f#&Np5RZ-A8Y009pm9G|)hKTNoZACt}>qBwjfg{wwa(tF+Vy1aNwP9cX0JR&JE5hi~ zbYvZ*di%_!vpYwCtW|1QDAdIDLzp(=8Uex9qL~k&G|O5NcD%>PHMgqW1ET{~JLDpv zi?PFi%ai@jbQvw>Dm{t)UxFt?m>$b-MQo)BJl!eO^eFNK2AygDGF6||_oqouV%60! z@nEk&4a(AfDw)`>NlP!KalAQHvcz-;`P6QNZHKytFbLxhWGpAqWa9FeeYqa#k=5ba zveZM%qGH%YtWjmHCK!-8ZSR*&#{XNbs04I(`9gw9Fc&X?ns4^N{53y^=z0fnPhM4? z%v}}Q@8DBYI`N5*SNoAg@RKH-2XE(cG5vC<%UT z2lSo_`d=lU!Ni}-u0G6TWDH|eQ;lRde9q@~__BUpaN>@BXRP!>mC84JKjVyzJ{w;9 z#gg;*vkBpcFqR(cfPiCkLSr_J3DWVA;9gnnK0XDP1n3l?1ZqfbF2C;Xs1nGo%&M0R zOaHRb*>aX)Ok<`~D+j7JkXKH8=VOvMHvgi<4Ix6{T4FKwHQz@637cNTj* z6;eXz?Mxs}iEmm26@}84Whm!HV*h~w_Tkmq5_@Ul)`(2qMSl-01Z2Lf_T-LYC8{aOyosh@um zB-Dm&1HL&NxJ+)xF$@&@0D=TURA1U`fVVb^_LQp0Gb#$?!AErYcUP4>llJkk?R$g< zZIRbMNZ`&IE4Oj<-;nNan!T&w-vin<7$7^KJ4TV9ZNsP*fa8@zC(Rfyk`9437(Hzx zZu@x*oA6J~=8~eSkJ<9JR+7g+5;@P^bqW5Vl9l#32#N%cbfGJW+ygcs@6Fv4U4C&D z6CE+J!d^UmZ2YZO0$2&0eB=Co@Y$&)JOc${&-G}v|AZqt&P~BlkR=(K$oVN_8#FnEq)0>ftRW2{t(oelN;f> zvuU!^RpXb?Iktjs;d->B0P?}+VAIOF1DiN9gSz!ufwH(nwYDz329t-cHu;T>PgFU$ru0nD?PZi!am z!t+s-YO3~LWB)&%0Hia7A%S%1Gb-AgxMX7o-qLlwKsfn=b`(o8cUIC!XX@JE5-(3- zSWi*~ch4>U3!+iYm4=JG-e*V(jE(964Z^?&jci8KAkfI>CJsV55~; za{Tcd0S)vk1RFs1e#N!pd40nUX4+b;-S=PC_Q}6H7#?a5LR9jryC$y3_rui1Bj?}R z&G*SK(V5;>$@8L0o~aadvhu#rrt8oSe+wngie2 zro^CgPgq9PG`b}uSR>$_e`lYID$Te%W1e=$_K~-?z2WILf-de(%%uL=U5PVaij>`C z(wnnmS+#Hh9X}9L3toTwuF&?d_8cC?dReT;GU<$~#YLeSBt~8Mou1VsoFy;7nOH`J zDg_*KCb}NX;Dp<+==zYy;0^evIY(qFkQ?^u5)diQx$fCbHAw#i?0FmUN=K~cZ)@1b zMOWK(G!IC-rGH)o_O`Wo-m4%0ERf5)`M9nC^kPvx=&s=2?S4aqTV2SYdme>mN^IFS z%RAq50o}=w(P7K`D=Q=9omHPGAJ`>0YZSN{2-YLKlzhy#MTsh58IS^-Ct78RzOd|h z009gA5$nQX*h*WtXY{U(bcvEpHL^GHtvz1jDRDrr*zoV0YNi(7&^RcH&Kt>E+#SnF zJ>wU9{)S2{UwYD4z!jZ~!3Gqt%Uu{FwWabSR-)0vxy@33_V1B)2vd3ONlnSqxov zqfei~T=3oVRZOv$_P4ok-ivC+k;^oyP`a>nX+-#1`z7~qCXM)UxAS6GXRvsyej?CZ z@7CTI7wMmunJb2O%=*KSP-~hMMMIm6c4l;0t9vec1Qfg*(RWq*Ndf#8s6e(R63^>X*>KmJN1K8c zIrCv4V3fDx4p3vE9no6AYq!k;?J$8)Hj1@$&%V!Mgv06$K&ZA3QT0ZrDJ4k)R-1;1 z7`;|l2CM4#uk|>9=$P$>544_w?Asia%cU_LFRg{F4+CT(@#-p2^w{0mxUSlXLyZ{@J4 zgG#_wPrJM^vv3lm@jx4EmUOl5zh)I!>YM(I>A$&czXfLjL7Vtz>xQ2o5+i`#o$pSF zlRDQ7HgS{hF1k7e_A__+3#Zcyv7ri*x^Slvo}CSqjm?3H;!ti&%1qVVnjy-=>C*Ge z#-RA<{8)OlYM~if6<=+Bn#G>fftWqgdrOPK#$X3h(NM9GB@nUwmOhm{?@xvdmEstt(l%dg{J4nzu=#5pp~6T z4T#`%dLDC)TV-d|Ca_VfBA;M042}ECl3o!^Q-Uz}!oNC{E)ffa*{ChO@Ob5PjyOu6H%RSg+uL zIta{uKBwh6ZRSwPdc7MEo<^iW*EK1E`$2Vu(Jr9q2&O0YE6hP6a_O9|v$(p?Glvge zkv+L)D#OF+{!WU8jTZLtPITXN0{wOfoK_0bf?U}#D%0&;0u=#L#iZ{?5xRFB1xy)2 zx#I@5D6UlT4bK3wS(?zwU3-@Nhe^<=u0;I;8+FWUyf&&yS|05ds@)0M3d#F6F^7Ja!!dG{{Ury+cuVOdc2!bI|Eazo17Kn z*!Fsa1%5+VOTP|CLVv8xqkk{vU?fX?&l+=4%z1ViZ;^^j$(rPidhWVprO7#swnC)O ziY?r2XJ{w+{r6<)XmllIJ0n!y81bQ2z(jl+mofASZ&toxXWH|A-tB}7H=~~E?3&Ky zh0gc$ab%PjY+VMMIs1MPRwtV7_i}-=?;DL^y2ThT8UJ&m*Q|6hvGV?^@%@8h0ar7e zzo5LHRqcbqAalefxvoPb&bK|Pur{=LV%8+@iD#7;^cp%=gKVOsrz}z5FOSVyBg-ri`@8 zEZCb_BUOiBx+mFFM7_MvbX#f+u}~Dtq$F&I%C?OVXsml515a=M;jq-$OPGAS{~-1p zgVup-S+X0_pF!n%?G)mOlSz$d zeo>VIHZ=F89TX{&uXf5`3}(&5--E#&6nhcmWs`&5EGsK4ZczdwS3d86A{w+r!s(|f z?^%CTS{^r6e!~Gm*UY^Zh<3YLXcsyL3|oE*hmn>I#g;=+x^h|HjH%g<(4Cgu^Z)ta#C*~ACDPW=UZv}bg@`MU2Qg8WTJvV0Hrr=Sm8 zV)(-IJ4els?mkgmrn<$_dC+V~IX#MTB$$;hzC-d&uZ?j;^1+bjA^gk)bjRT<&JkGs(6b#X$?8Kl%wVUxxR1}-cqc6{^2@{ zOa2!3=46_Ec6mz(Q0oI5D*?GkkE{3P_wo&J@_QOYFp2aI{MnRusZ)*1K`zb$z9$(e zpTZh=Da#bpE_$|-WpCFMrexQ&#+rf8V^V(^PxHRurg}zodO%KEo!K!hWc zVz2JX@sVHYXY{9ws~G5(nO(h|L-1gFU9m!oF{yLdKZ->HlD|)$A^6diF|<)&2|w-9 zruGVvu3gu)mi(;~q&+5O`nn2DVWIpkT!p415}Z(Fxjen*f^O)wxzuGNL>NKt_2h( z>Sc~umCE8NLo!p)!X>vPiBNf9lBi9!gbkG1pwH{%)SWhSnPsHVR0{8)xYqlzS|Pjhb(lk@=tw$H zHHw*^Z`p3IQ$?A25&5X}Q?wK98yUL|2yi5tbMGUwNyc5oLFgzi4si}v+z={v$fQy@ zHB-k1AtQ*}YhP9y*}((80Nf5rVQZ_%%(24tgPYc6fE@d=@HHpIyB4<5(a3QDpblyqoY z42-A!Qiz#Cp?3p^1+Bv4JlPe{PIM|y!?RcMyKSY!=1Q7wb=(J@XxO~K!myq4PGjeo zZ1=J$XS$2=xo~`PT04zF;Dk&baHWdI7DV;jUF0dvnri>aE#U)QY+^wdn_wVwexu%$ zXzk}&gGTU0%rs;jnX5H6Ko!QSv0gq_g;;vvfTyeTBE|8MKYfwQuWLY#v45tpOIA{m zN)O|`M!6_1fyH>9GzDL!i4Vb8JGXXIr-76Lh!2)53@q|!8FfY1p%cL{L0_ryNXa_|PyC--H#T^y-30)^fjADZ4&?uQ`K3R7>QvbFS+-H_*Z+;*gQs@~L*4 z#dcXHqcUtTJjw^8o4x^v07QS5dc>xNy)zvszFJ%dJjtllS!>2cBaA?&%$liyFEr@b z^9|~f`?{Ju7BZ$XsAq?CkcEU~0E+gK2N_ol8~CiWX*lt4`>2KzwKS>PBZHM@v+--NH`C zDIJhI+7k6@?4O>R4)(rIu>qRDn!2%=m$6S64f|ek63tZO>hG0-S>xht@OgaE*`itv z(};Y&yf|lnu94+Th7W+t%q|7%7HZcybllC)E|bAbQ)sl8h~jvg&%fUeSHdz`4+%uq zRR9JqXg?7z?6kGm4M8Uzi_m@9|9@yJ;@3pR4zq^J)d(|Wr?+(leJ;=q+*VZw@ulwk zq?WQ65{(3!i$>eejea;Ll?gh%rcb_{l=hRjGE**Hk|P%UeO_~B4omw{{)-E@&ihju zWOL?g%wTDE(wo9kVT+NVW`?%zXqL7^*&b{}>0Y1W6cezLtLE8Rq-wfZT@QEE`bJdY zie4PyY1n&CK3Vp+dsrLx@rwsowRmGXSqVqAB=|Cba4uxrp+!PO2wiX*#5s0{?38rpojkM)kw zCp4I_?}IM<_{g7{D2V!;#TY^XBVqEaTYZ8%c`USmcCQ6_$!=Mo{&=CPY`6kKI2~v@4V&xXQr%CRr_a#Ys z+?I(|S9-Hv-D2>qam^1syQ?XX`mNd0e9#g$rYA*;Xfiw&Fip7+E0WN?lpo_V@*W;^ z3L@&E_lyt6r*ehgKK>v|nXzrFOOY(o3-WUuKla4t*Y#u*d#|lLF*u-b?t~*->5T4CB&x?eMYM`Qe_kZQck$z}4()bG_nMC;h#X02sSL zw>TXjIygT+{`QFRVVO(#1wt;eauI;&>2j!JC?o&AQ6vPf?)1F8iUZ;S6LnL)=-pNn zjd%{GydU?E{ujCda`lmK@S|mp0{p;11SiN*2~zz5ul+RxhqwQQW3oF*JVXc#gP>1m zLBk3FmZ1d=E9lS-D+ud2_10Yd)pJFG+Ux@!nj4}y8CwsTRt~u#qbhBoR(t5b?3HYi zxR>I%T%gMN$@REn1%MhzRfn&|1H*QY`DdPi`uc^7-cpZJnv0LzAt62RCC!KU6Q%Iz zDL6nl;Iz*9>tTQY6m;sW6lc9|qla9wA8Dw7+t+uR7bXbz&H^P=vvSs5z(uS$v${HY zUT@uHWvl#PPe;U%85NHv7N-WyfB`&Y9`XOV$xnCuTg&uZa+QYM~fX;y2_5ZsKg z{3dc7kpXlV5TK_OIkDk`a=-!FjEx_r$EW;V`(0c$J*{AF{T-@1ywR#ZBe0?OIDT@* zVzAR#fmXq4ZgGA`{XwL?M>!hWHQnrfISk#Z#r6PUw}46&cTNHlukEIOV>fDJrgLE+ zQ>`V0{=;%L>QHpG{=x!b=SLoz4G(oX(}4_$Fea5+M2YAsXTU{)_H8% zh&jkOshlJZR>^_JcDK1=cG6bzPmO*2MgYP23?ry|-(BN6l6jCS2GsuGJEf9lmHa{o zYx4l}EL$}0J#eMd4tm;LQq*j?;x+tWM<}7e$=CjqPo#qu+5uaslQ0N|1h9F9C`h7z z<*oky2F5m+7)do!RS$f48S*yVRZi7E1aCxFqEM<5qRg^HCh(2F6je;n7X>N@;$u z5qY#ef@aYnLj>yVslQ*_bN6zDy;YnT#aO!F^5}Lmao7*&><2rQE9lXq*2cLh8Kzij zlc+q6n?|_pvu+2HsdixAH0k_%&jGYHeKAZ+jJjtb(YlP#|7>M2z{4A|_Q;IfF1 zgDK1)IHsT($NYr4XXdMb+i5Tg>v{K%r1s_waI3eoIeUu7!_tQymaVmowcodmU%vE3 zbaC`ag*barWj2DZ7dKO5;s9PKf6cJ|8Q8NJV3q2spKne%~quFok4 zTOzZa3cB$6--Y+r7oMVMOmYrE6u3tm)vtRjQXZYNFAgq-`go4-1gGYTE~61%mT~MY z|LviVj|tsCqaz0~rNKQq1ApDa{#cV90@^^2N5{*UlQF15Qx_yP22Q5rzq|u=Fo@aX zF1`YExWO6mU-u|Ko<0<~{hXlTmnSC|(L(PANq0?8!o|mr`lliFQ^bQF0ey3R`vD=i z#|F)>dyE~2olxkML0tYby5ozy_{kHH4=+5)GyIn+__^ntL4E?@!RPoZ0-LW{i(@#2ZXTTKFzsx_a-^?xPyqCdr+ zS!g=wrb9)~+fI}v2GC=A z&tgc*|E_^OMX9YeXRSGn5qZ207Aa!PT#wFbwb7yX{WV4_5VC`iZiDDqX~Nb4ToFK` zCmlqrH@C0*&MZs@+085LkQQdDvImT}{M|ZQ1(fwi@RB@+<=?Fx z&j_#x{nD;Z9@o3)(ybs-f*;}GoII}361m}ddnWe2lY}oZGi;lJ4+P#Q ziSDRA1u-$X$_eVJju^(4QaQWv3MU1vHm$^!YIvIYi2ZG~?Tmr4BuIi7B=n8~12oM( zj&<*OJ9k*~4)4Z@3V00pBuPOi30YsU+h>gzr-7R1^o)!a1}U`d+c3t%XLs=&r}rK; zW{jZ{s)mY{uL~~0vH`PS_=^u@?VI?fYh+^xk95?dnaBVe<+}^5{NyTHH{Id>oX?Ljt|+iej?rFn)P$P!}tr<=}gv#VMh*zAwuc`XWBR&&XO zU1^EoNqX6;*V~(v*L)wjfG%yOti1gfvh66kVnTVh?%iYYyLb_`vjh3inj@a6c7`_ap^59Up^^U}D1l23! z)1L>yjH$M|E?gbSr;EU3kpB^k<<`xqUgfH?q&1fe!V{&S8uU-l;hM9P-vFd{>Pf#s-GbLpe6$<$H(G7BH6-RDW?+v1jrvW1EkReLG}Dcgd& z%~5lb;pl`a8i6))7|x*B!{;Ae53T)nRCndL0t(iG416_{w{!Qlu*Gg7) z)k>}%n@ZG{$xII@2Ko6Wh%dFLJn5@lQj3{vlm4G5545W)cDvM51&a=Nq)EtSwmwn= zYi9_G3;YoR2i83a?Swr~&-7PhXP zmFY)Df60qp_5;&()+WUDCpikOW-fx=yXm&m?1?||FT0{EGt1U1naz$thb0pImIyf_ zMuDFQL#1{T34?PAN?EG9JCRo3^OCe~`w#`#R#uHv^y70xaS>iI>zW|d2c-t#?&P0u zNh;3*RK)hGB`m98IKS*k{~Wv{)xzqGi=Rrhe_TpT{=9cu6eb5<7 zpE6C9&YT713*++ClJj)NdWJZXG%h4bl5S^cz)c$pqw^$po}w)CIJpL+ z2;)FzUQl4kk^A3Q?L}pQ8hG19`7}@M1lbEb-@4 z(A^z=@$vu(u1a|$EFRK&esd*>mYEYfVY`|(bCJQ1h#>^_)uHkB!*?i#kb~VxcYc&G zq04^y7+>pILXGS-LR#aVA6+lLz1)jSfAmebV;LR6tZ%rpn4@=urQt<>F1OBn%A>a` z6lrOruAHr@kWXyBl%oegSA~w+U*B0Du^s~Bj#v*7SyQdbY2w+3+Z$hZ8d5<~*$x3T zlFk8xz}B2Z---pw9gY1u`LcE|9fPS({(!bOHItJYq&YEL6`xqU``Q*%F|080^-66y>Y5fy#q`BC}Qfm{76Y@p1dY6@-IRL&Mhm z?wpUdYxZb`cKM%F2t2<3cPd2Wu>t>^C3^N9*dc^?=(kVk(4#TvO@Bl8KUsWM${6DA z0??ENt{m9YeCM~%r&{OW0jAn>u;5mlQ3(}3c}k3M^q$z= zuFU8JNNaL3mz!b7sMl4V7H%fn#Wy60?-FU$e3dA2Ty_M0G{q9d;<%j&Z&-M;_wj*$ z)K)*eakx9ee!7hZq9GqZ(iZKhUYfTco!n@!Y@XY>aBBTW$6F_xl*kSnAB-zj{x1~e zrMen+*md%WRhgb$Qr%q0>V#K_<>B9fgbO0^A2fV@oKXggxc>y=yr`OW*;)CpKclkc zbvG0duXr~E+dFJz#sl@Rfs*3-mujwCtvZi5H@ZsnJto&)6f&|Hw2DCv)~r0>67L%9 zhhU7l+fYTKu@>bbGyI^*wGr-wPN+Tu?%bM-8&PeDr}?=X$`t&sz1dSHiq)N1%dKtf zJPtl8mV`)z=M`$QVB+8}KJ4C%%t_WTe2q^e5mUU?c*BypAYuinasc}=^aN5?!09f1 zr>|sXpU`Y66jS9rio^-Mof6S%CZ-~3S1VS+#LMf<{*wffd9eE*=_QnnLb zy_XwGL;4S|rw;ejThnclFKYh)?EUPCq(HongWT!32e+ zrYy%}p2=3P^u{LgV28ZfG{vYB_p7hi^93LuYpJW;J=s}G<_!!1YFwFOEg{XBh|zKf zs(J}U*%>t7dOmO=c65A25XcoWBWwC>a>LZ$RatK3M!`sw%^q#HI# zZ7$N;n=Ou%0o-89XD7JQ(t&fe`2kHZgFA+g z<@)z_awfjTOazQs_Uxrv@4~X};>WtVOPlls402?3?#QveyP<@W1)G^I_bRp7`&vH0 z`wT{nXLv|#Dz|Iys9-y8kv%h8x2bNMjbE*Dy@ZED{AHIH&wN{YtQ3#3+BvN@;&Kb_ zET97W?3T(Xb7r)CYdm{F&b^Jr4xrwh5FK}Zz!+89kHd#;y{ zwFHSMYkBXZiVb<9i$iPlBER^ot}lsy+`4U&ADI4xm(2sUOcAoNV`*WQ@^8}&=I#39 z7oJT)1yQbdPv*6z>eQLwZSz6lKSbh}AYjYZOkr3Se3C7?R&|=3ySR;^Z+E_*F&#U2 zo3HG4R3_CSyauevR=30pKIzr?ivQnW8UhS>QnVLSDm6%ZIdwGqX zaiwH+$Y_Z*p_{XV$Pzq#WWj*f;{YKYaz_h7u`--{`Yj>qnF;$cE-5cI4uAM(y|4&O?DW(i$sl2o`_F&_(iNm;p^~{r>q$B=) zBNpd;u4f&@ajmw}(GaXl)$>`*@T!MppsLwUxr0)?h%U7}1C_)% zQMG7A?hpo_yvmOPa3zxHnav#Cz;}?Ygj!}LH@{HU@B%X*I*;mFP^@|_khqU2h${vf z5=rfho4#<3|N6I8t%kscPTeV^)*djSTlA*)&}j z?@cCH&}%n*&HYX-xzf?n%gjD`?ba$iah?;GK;p~BKcpd|M>KyJ;AE9=3^-i>+`;Qc5%1mZqOJ8m<{GT2$tC!2a4e>Ae=n- zGw!*MVr6JmpDRBc)a|d9{j$$sb@jTiV}236f}wWp*R-avc06DHnTSGCg3T`d{A9eY z+*g**8U`&&JwPMBzD&4OjDXYrsT*Pi6z`*0Z73U@r4+xk6Sa~=c&EWWk>XPccq`qB z{w%#PoxITyBNHb;qdWa^zRz!tkh(LN{M_vc-qSL7%m(FgC=i92Mq`(f*vt3&>kZVx zlVT&PTzsGgj?PU+cl1cxGvL{(cB&Wl`&+fHewg1=^5w7(dhu*HYY9Rm&V#b*krKr= zJajT#v>Xjw*3_bK?#l{n@OnoY-FFDdbk-d}DO(np?4vHEHQf#+tu|1zZz7kTkx~w) zoaeqW=kW+PTasiSS5(3yiJ$A{BW6zv!Jn-4ecpn>wQSh7R|{F@m34!@Op4 zP_+t<1oY1wGG3Tj*&YUrv**mL%vKBro^0H|P2Kohia9`H#WNQ7m*9w}Zys0Fimc)oXB-=z1(UG~*VSK`v>q`;P?o;c@iuI{T%K9K5p z%T@W?%;KXfG_?2{1yBxNj z+i5~M!W>!+=4l=XfEE**6Q_Gi)hHD%vOmAln_EetyVdxxedM!_(nhC3sYSLDY5sQ< zqi##?C^F^sTdS$=GiLYJ;4^B~TJ9n#c|?i6bRK)g>Y9iYT{CB42rAzAZ{>8J=ISpBYU-rnUrl z;BWEO%o>4eN^lB}xNooWDIW&k*Gy!N?F`qPnBAwK;Qn8qZVYLmS~qfT3$L^1m^CZR z?BR)z33Ug%PB#Vfr_b#lY2aS#;R53vt3zDTK*}*&i^Y=15v;mdyp)60Bv9pS6O)DR zbisj)p%?2@61qSsCU1oCRU&a~TOg)#pe(8%``K4a$hk(gWWPJ#+H}P$HhYx<7r4#D zU>0r}h`9&it$V8YvWZW5?mMntJV0yh^L?^3#hQa(^@Dzec{*~wTv+71 ze(^pl%OXqTw+h!R_qU$L1a;}f7m!lhsM>7?sZcBM-jCyw@jBy{U4%+uy=a_WHWj_I za=mk9e8aFQ_6E`A#&_mqt5YMzsfmyoe)q{T-kC8&7PecDO-yzy#b18(Eoh0R|K3m+ ze<&gixl?`fqH#rIjG;_$x(7iaJ}8*)6XD(*R^@^@+TUfKLt^KY9pbs`qa zMN)aC_nog!mjCXZ8cq^CJpP$tdvPrA{FZ5gOL0J0yHX=2{x#9bGY(N3OPM86gN=}8p|W15RO$9jD)8rIa6kl;+Y&7eM9(w4FQBl!ux z>}rZ_vV|7mn~)iK{e7cF0gv-r>m&_{&i+^y?H77Zi~ejqku`a5E?%g0BN>0VHY!_xcygu)ADz)h+INen}PdR7$T_HlVw=&`m02^&Blrd?Mz^zE1DWoGyZ(png{;C zkVsc(4eRhx3zKRvSOzQHlWBEs!|>)(m+-kW2RMCWPKdK!KHH6x%FLITRc#%&DBn=& zG^{%`^mqWfc#+qEOp}C}TD+z2_Q$*Y(5bdp{4<^L%^!`M!fEdm*)PwnJazV=8ZJ%e z**Qoe;|oRqxr?n)S*q-qg+tUQu=yh3h)4$~&O=xa95bG5C#D8kFP zKLYcMzH7F01wX2Db?3H+;zh1S$q78tmq z=ZlHHxt{o6FHC`nX6w%={-2ldYClGp=Oa?1fyKS6{01+vIVlB7l+(+us`_i?+1>&U z60CFHpU-~ZlWWQKl^0zgmC)BWm--6(IlG7?*6+gcc10MSM12X?XD@L9;y-HUh5j^GaOuHji`Rc z%BJ_or=O7|vV+{==FQkqdEbd4HJ;~t9F3y|WTtlOA`Ig+n%uy-BqwkZ1YOk`kA^08FFj6eWWM>kg z31*p+A>FlcRsEj*7wV|Osm8^(tH$~x+f@sjF;oj5^HZyExY0U3yt6)bTnm89(!Y^e z>-&s=1|+UmM2x0X3DR4l;kJ2E1qIIv)HXv6yIo*bYKlEYvoIW6F0kCyAATK$T2gr; zsJ|h{z(H$KRL7)eoUeN-#ujau-ThzJ)ane>kjpZAAH||L1V76#!*kwc3jF|-)^0hR zvZiU9b(z-$RGLdWv;9=217@r2_wVV1U`}^ziB3zA=IZQW*v0Ix&35ZvVUQQ2kffG- z`8I6C+h46KDc$m^bz{-iqbQDCeUkJ^5Yr_gVuUn?ro&|8g-QJ=dA>qB$I5qPD-ta^ zi-Kv+$II8Fgjs-jCOooTMI6nQB|5K2pP98XV#yMg{WM`Z-)=)yL8uQ(BLf8d^bHoB zUfxl+?JM%j;NiylQbW|>2h8X@Mq@p{QjVH%5+4(j)*^0yB?U#h;b z>O~3a`p3Yo@%fF-bl!NpcyCrU>wRu>ftCc0BV~m%skua0eUM32zqPbKmp!c+{N;Fh z*sxKqhlv4=Ltj%&C$vs5PB8xUHYr1L1F|?m5XZNok|oKVu&-HJRzq2L{hrwxPdtOD zMAD;4+L&}Uf8m6~ zg3FDo!9VWva;|=_NupHbwJ^^n;2_0oPZEQ6Pgk*t`k-;ranGW9-x8+CrrXol-S5yn z+Y)kD+vGzGuBNj9)yV7>Ou!m>(sK=CTxdccnSktoc6JIzT+6|GMdb z$)}h8pebZ+Uo#~L%*}kO6CdVeEr5Qww5c#}y|>;!I|Ap%DmC$6JlGzqWKTM>Ab zW3t5ySzCVrdy>C^u0L|+t~{~4ah_S^`>X8Ew}pMSGvCm^0(l}LB1UE9$*tM(3tI~Z z7G%+US3ZG_5Rs{gA7~!Es{8Wwy)KuFHx2|tGU4Wn1OBts241`stoCd=;%}kcX^jNK z$g+kI>p{Ei0^ae@ZreX(J`7|8R=%3vFwj|xLqax^f+q{#y_@bg!_3ln+pWe$ZJjZA zkKGox_NoB$qJLVPmhq6{1yMWEU41F`FhEuAAx(!J+T;G9;2J`^)k=Q8a!J` zszvR+p#?t2kT7)q&Ih}!wb2?V%&g3?}=?{+B}{YT5ERcnjJPpx-l+AIgKA$c?M;ha&NM2vygzGCbQD8&zC zwccl43Z!@xew!74XUFaTu=dqqQMX&PihvRVqBICdiiCi)goJc6ARr(j-Q6Gvh)7Cz z*U;UeC>;_*r*!Agao_m@zjN<7=f-pW%V+p8%)GJp+H3EJAD?TtaVe}WMX5t_BLt$0UbpPr(^I*l%-b8wk8-lN#98O? z^&1T#uUR=dhsCR^*FBJJikscSVp4e&1`+gObEy#Du1I#ihk_npgdu@mYPO|)c@$Gz zig`T#seV=)5&P0x5Us4eO0o=p3C9uicuqQklmb-VIr+0iJhwP8tm9B;u~6u7QjnCq zirb4XO}gDQLi-zx&?35HP(rjDn{Ak!xa?YpVXCaA4vZ$#!yD7d0-k^%LR;zJtUul6 zd?Fzg?{oE~Er_lz%Y5d?eol(JUwahbd&-&BUrwEYAVR~wO)I9}Hr|9pD~~x2j}_ZD z4^{B8`s$o#z`-=zWfaPMqK#pbwJ{_GNsbVD3t~!27+#An+6Tej#24W_gF_Vq4#nFz z-~CC)?5adGVC`Qt;1Xl_RYsrD1r50>PAcZ@SCKkHh_Y%CflTb^n&;Y~>;uwCH4bMu z@r|l?k7cF~Qa}Od57sPIehHe6a;=H^-Mr|X;Y;oI2vycAbo zo$m1jp6ZihCN_uBAR4mL^tTTCPjjtbgCpncx+Na9(9b$Gwabvwdgiu@h*9h&o0FQ- z_un>!()?`l^lWDtBz$J1(C+efrlV}`)V&Vl;uLObw>3$Gf`R{iyJ?@G(#`Zq2mEYU zHE{no#yJG!a=B#-{~){N#98;JFd5~qOp#7Lp35;ABBTc10KEn7REec`UK zskV=U5b)^-3?^PcdF?AcN*K8~Cb|C(e&kX{k;3~P2_a`+eO_<0snU4B17z5LriIWx#*i* z6~*bu50#B{2j@S$q%d1~nssTTjTBa@Mb6%lAD5XMexGk^(7kwfR3w2!O%x;0uZ-sl zm6t?ApL$4|#6y-ZJ=U+S2f|MHY-avs6q7@#05z0SS64^nytlA2Rp;353^th^Z1Mz# z`|dBXz=!1cs7qR=Z7*}jcyRg6gVf`Y+wl?4WYmHNF&I4 z^{e~lbl0r?YW-uv$8+C)5wWF<#O|r;N)QPNf6^DnhUhuhR=p^}jLmPYu>VHr@0JSj zFUQ-9u*&ffEz6YnlsI)7gF*^tMdX(XrTHNc2_8BKB|()@ws4pWxie{25W5UXk^AZ% z;j4<;lE*@anVoN^wYBLJ1cIRtj7=5#+#M;rzS_Q()0ooooEZVO(4JQKW71MkU*-hO9w@8m=dkd4TTYquduc^2l z@4PtU;ll)j5dD6pZeG=IGSC^0$jbyjMIPF^KOXLG>IoNs2KoM5?9C$#9WC4Du zXyzb7z-^wKzpn7;4L)ngpJ{MCDt6q~t~hkuo`$SPa++&w&P?-!(R{vwMd5N_fa45tQwY>RNGTmfu|IhZg+lvS_xT^va{dRWEt;8eL(YC=W2 zhAFAAN(*M)Z*dRX!Wb>6&w0w<7cesm9u@S>EDF`X2t{){KfY(X)UEiH)ivCojF0p5 zaMP6i!DGQ>Ak&L|8~b6obB#|4Di*2Hk>NK@(61lhwD+0E%p6Py`zh?N^YE>M!)vsU z0iO$Gk>YQmV(xIQ7_X1N7g*jnRqqw|mJ#`g1^KFC9R4QBhicQj(8k8#Vu6QItM&m{ z;7XoNm0YD%AOQIF*UYWHB>t8h#q^!yUA=hQ$Z*^Mv;H*S9vuq`Pw}GH6}S^s=2gz_ zxg90c?i1AJ}(+0IMhE6iPsytW}$b*nz(ZQ*A!AUI9d|X#Wo7pZuei)z`!c&uvjgw zaj4`RlhoR;zW2Mk?sg$m|K*Q&AjJ(u59K+v|ETh*J_F^};;!o`YLTXISo}x}Kv02D z^^r_@b*K<0V6quI()BdT7}xrnNTgsACxW)6E2HClM+7L3FG$X$Cz{|Vo~!%%SF zy0sn`r?KB&?f&|q3|pnnh@_K$m>}q>4H*tMd_-CLkl!VS|1p}L!< z406QgeyjzkAem#>HdSl?M72O8^QCmmQ%ZnYvo6?zxw$>gxv@yOQ+nwnaL9qdDdF-J z;@RFf9gAD|_2YAow-1nug?RC5x`PY7aoVvird?Mm>C2xBW}SkMW)0d}Dp*W4@>H2B z$W=Tin>=+IJTLn_cD>A$@E{ENo$HNGyT70&DbuRCN;E*Arr!iQ-xi_b2ruc#Z-#3=m;@b&<;bjP+#5|T3(Va7@udIJY8qfh?LCreUzSC zobE%d@4CB0B{$>d>#hN557K~0uFjO&p$F!lE#fV`E|HiyJ=fCx#`-}{h+#$YhFm2O zlz0UA?3kyzNOH*nLDuuFxj1RawA)j4+1{T9v*o$sH-J-mYCJ$~->XU^E-x>Sw+1#C z|79?#u|t8+V{j{jv*nY8p`-BC!M6NgX(|Z`{H~R?OVZ!idxM`)Qs+LT*96ACzfg;> zOv;;$u7P-Ir9YkWMOMmqf|g*H^8^$fs0s;eM&~^%-++G8D73P1xIj3W3ws90N(OOa zqvZQ?;03Zq5|BH+ZQ`Fh$L^zf}G1*F^~hNS1U}I&UhF!H~d&Riy~oe8CR{LHxZ;1)digs9ajg$PWmzO30(Ta4+7Uw8q1k!j z%o-lxs#G%2($d0+`S^$n)sOg@ z(fjk0eLgm(=mTqqi@PSUhH{rZlECl?i3 z+Sp+mDU?_*n89Y+-~vCO9h?V1hSjcJ!Jct@9l)QMaRhMq!?^om5Ii;LCaidf>-VfM zs8OQS0GF^TA8YLo6TdZ8w=&bz6xXPt6S)=|6@Si8q1y}aPtMNeA&_(Y`z+aANT;Ipm zj!Wo?z9SLI%>VsW$y+hJ+At_kE#MFV6XW}gWbE#%oD7_Si*!(asy7it{H*L(jqL_kYv)s|BllUBa4eXyQ(|sm0Y>h-W zP|8)RUWsu}%ZtJBDqCj#k?I|gSOmNrb1hXx(9XaWzJ>>s%c0&MTHi+pK8{>R#Ujk{0~V6&3!S{hzA6R*^Y=#g zGaNn#vp_=DZwBP^l7?-t7G9-(r6Mz9Qk|LTomm|)@{ZxLYT;{jL9&&Qn)31D+#*H8ABb@QD}5~?i$h4E_%H6ETa58Q<4H+3qJuqR2x z%lX^ukPnNasyHg!ZQ|D;2Zt2FEnwv}^ZfQ|BOsf$>Y_L8b-gRUe|G(gf8Q|RR)8#t7YI-C);{23R!qJ|gcFh!K(l@+bVR$t1f~EKaJr21=7BPj zkauY5UBai$2Kvgdm0yDIl5h#5q}~HiAi_{A;ChIO>kx62*06bTcElj`coVeR@^PAt z-awurd?}n7QN%+Nwgc? z(45KJ*M)nlEN8R}!W;by?EvhhR^Wfvj>93F%ghMzGdI`P)_zs|#%rn%Uvp%K^!Gt$ z00;epRMOFJF39T%0IIVt`xgKG#Q)x(Y-H+JG^s5hn2HIadO?b|EHNq%-E{9bTpgs7 z0Wm)CGRo1C96tc~j=f8XhXy2>mnHO|c2h-Hl z6r{=TF3BUEMmPMjJM|)lBilbyMPdL66IZN4AHflAzBO61b9ngj3$^6WA{{|{xvQ2) zx!(Nb`lJPyv2*lyL?1NwP6LS8vo42_E_VCV#i6*%0FLx*F;V_{?!1?Clw80NA|N0T z!)={5#-ZEdC+3GqghMMsm>>Xv&ssPZxEW%p!oD)@2;3hGaDQ?m;hsjsNdBn0#bc$6 z_sB&|d1Ze(cZDr*{UATBLBF(v$d=2BdQ!AX?ZR&l?p+4V%U5T6Zm#QtjAMmJJSNbH z|B2VGU;oDe-w{J9V@_(xSvTDIHQ2^d+Z)!q9*%F7L2~xj!sjCc%lP5lr?-zR@^e(p zpM#PzWR{z`_*Lc;oDx4fZMqV8*nw5d^j3{Bk7~p9iwON3NT&&m6l9UT%R>pi0bd_E zUX0dJXmoS#G8in;{-g-Kkc0_dae}?*bWXPhVH!`6q6$B+VQn6n;B`wAQP#dEO`bC|s2W#Rkd90Cmg9$bzSO?$hU zM)z0MR;ey>xRdAv%n4)r7#p{o`$&0gkbwf#cM$&-SXi#}r>Vh*_y`zZDS$D0QhD3c z4a$(Gi~O|lK1nq6kK^-(`^K!Bvf<(O)lR#Q40;ocp*Rf7j9h3LBRPsK8|4V&*R(pA zJr7{wnys>c;HLRr5})-ipPu5122-b`Yx{y6iLm-KeP`E|cV5kSz;RnOIRDC#(c~L5c>CSP!9#**fIJ|G%j4iN!sMg8_ifIjJXc@rQwoLpR>^RqZP?6NWw)^-=v^mM6m z&N6@#0pi$3q%R?z5%65?242vxZ#=w&z%Z6=!DO!*-FVVOKY0VN9@{hKlybWiIHKU` z23L}JZ@Vk73q~V_WN+Jo3!th}G(zt8qX8?j`f=?fk>6F7jNpkXCNOer6{~!Emx<4v zOL?EE8r#E8dHA-D$~{JkblMOuVL4A_zCf#vliG0hiPs2-t@1$YStA*k1(Lz? z1X#_DQ)efq9BA`iEKBmmVI>e8m;;OnK-;8HmE5;QBz^w~ohcEa^D9(2@9W*GevJs7 z@9(4jXCq~XDA1VjHT(mZQLF%l8}pQ77L$H9rx}>q&jvklu?&uq6pBc}N<1>0xi@I% z$TZ`T*MZ#$_=ruOYmiI-I919uUL`o909XSnTiY@)d3tN=RlQS5?eb8r^5*n}QwjUL zROAoE^q0AF)DrjtZcg(*vn~L~W~|$!5Nv$AQkhv*|CMES|pt@$DBNnb%=fK2iKJEh|Q{9!HsjZLWH`l!oBZ*SMo*S6I za89WMwScHim#0s96Zk)Tx=#!J`5JI&lrVO9fliZ0=#BV#^0pB25dV8rYXE}lp(ub# z+NKaY%=VF*KO8q5-UD($k3fmAN4Yo-3Eb8)>$H4(4>t$1t4^Qy0KEtF&NZ?>_NHUm z-)C+U#ZLdSHMDM*BUg}1;P*Y5r3L$8rFpLxRPz57##X-s`!P~&qw?=;*`HVE61}_D z2`e2?gp!dGs{RMj$z*>-F3rL3eJI0e0zOrjq>ZnB9RwH13fJj)ClwkK&1I?m%w$MH z*8J>n6M$XcadLJ8%rx;33l9BUBiftK(B!0q@<3oB5zU+k5xn>gHjctea*UYEA`qDQ z6)o}q za=JNQfdQU{3`Us*fLp@hiVmz02a0BvRzK7mBWY|sRibMUEsEwy`hvP zgNCNC_9ximUx)?xzT9j~DYD9lESW7zZqAn(N(JR}K~K=PhE_cW4GolS6=LH8S|Sj|yLZ7_KY=w5}Ra4^o7 z<|_+uK5Y#Sn{m*Dl@WgMuLKx5yp=GMFO^7Xmp$whvnssVz)I6YW0j_hzqK1=@Wsf@%Vd&igN2`!E%&ax~y-??Bhx zCd;eh8vqm$K7Dh;<9P12y&SfHhAJAuz%uJJVs>?gwK}hlbiQKCYOFE2K$H-Jzsw^w zs>ta~J^|f&Y<`F|2iP8m3u?P3dZT$iPk;Tuz@v>`HrTe+8LtM3sXy1;YnB>uS2XVS z`d%+@H3;b?M#gO3{kzruUpx-D4)4)cbV-P;0A1lv%2SF@tN9Vo3u(&Pa?o$-Dka~Ybf>e$lI?d;hsw%Ff-o(7|3Ydp^ z<|19Vo$6)a(}JMs7vmWrW_O97308XusE=Hawt^Nq z!sCZu&akQ;nN8JlOioT7(Bkn%9DOna&qhl%vcCPUkZLiQG9Fw8Vi=Ro8In)9G;DWS zikz{rvGINd;ZQyY=G2tE*sS(F$SD2A$5F%}Dm`WJy$An(L$Yb`32n@Y=9bNEI_y|rNqC$HKK&9QHxS-A_5U~ z{nh=z`*gwTvx>daPi2uzN+scS0A2|p1p`>!0>bIt%ZuAET1r;Eb|r5&_p?LDQ6vwb zE5I5;!lB?) zRgS?;69ZqcIQL}8Cr_KX84mXmu6%g`M6(LDHF1llD$V232|G`~XuWj6zm}4`(;O+( zqWt=7jQW8(U~8D3a;jo*`?YL0T?O;I9_H-ClxwOwMc5W;Hz;lMjL9c(vzox5z915q z1E4unD6ig8KitHXeuX5Wdd7(yA5t-T&9OQ6-3Q>QiG(p9KJ@rT1tY{ux%N+nj zl(?TcKzvnszXy|%;5ugspgpU=oL?;A$({{+@-K09dZ!LJzYPYYq>2kx(h&-!7}_7+J+sF zG6lrwuzapK8V1paPoM>q)AR~#*9*X~`v3}l%s$L24*BFe4LuiPk7}ghLe5&}hZB}R zpNMK4UTI{5(DfG}&`h{ zbV^w#U9Vv?4+t|8_vc~Pul)B_^%A;|pdy$0lCjCj$@5%a20W02+{xFdV0iR0&}jG) zVQjOW@vXMK2zkh_0_W{wwglCoa}|IMiu)Fci044=QbnOxbwvTX2B>9CNNB!l0WnAw zn)5I=8oZvT;If<^f~xegVwk@CgewNY&j;u{^yBJ5jmPHc>d1tP+tF4cx~^n=0eWz& zX=CduV3e|&(~xZjGbHs$l{We6Jd{rCz5Wby+@fr&o=-% z@|Pa%N6x+iPVpXt3Voi#g%2=u_$=D*pg9c7_i1JP5&6coTn`8aq z%?EK2BPlAZ1IAgbgDKl4XWY<2+oF^`dbgyXxrYNXK|@E1rFs2k-u~tp4RW z`gmtG-~kcDS?h7!GWF3vD0S}-h=5!dkNftu1D9r727>Mjz zEt@X_DDlW2%n8{R}QPKrN}|&KFGHjP$zc2I`{K^=kkB z@G7(DH*=NfAe|Y)dJFAgTGklBtHL)6lQFDs=^Ewk&|lF>ep&eZ1R3?)ffI%&a<#|h zjgr`F7~+-=NC=N~j5g!nkrvB?HxzpqUq}CKSL*-i+IUAJ*4LDuo8l;< z4WH?c*z2h0`r`bn`M>^(zt6_?1MlyGZ*88k^WZn#<^|r@uUTwS`9Cs0jpkm6x=^_( zTBE^MG7eLfv&v*lLwWG$XGw6J4o^AIu{S@4Bn#;36y5YEU^?Y`YPy`w?KH*E4Ilqt zfya=p9){bC-G1--Q~c}F;P@b@CrSZJ+3PQaqzEj5(D$W+|L`l|n{hv~TI__V_EVVA>m0)8CL@k-Gc4B!K!*@T-+OI_8!iSbgrex= zmlG~X2~5}P@Eb@WwjUFGB;u#l($}9zxEO3JrIYo^(0}?!UY63c-#;n8s&L^4<8-`1 zLG&Z3h<197a-6-zo}jm47*rsQgT)>0`oUOJ%S?uR7BH$&p;}?ZFa!)S>nE zQ4+scZnuSz8k7+<%$dQiHrud`>a3Wx8{I#HhUiCz&>;hN;=Uw5ypLBZFBH&xP=_n$ zMn%j9E}KA|B515ptdf1mg8Su1P+$NLZi-taa_IbQtvg6n6&5BC{JTB3La+sf2Ts2a z#IXao+vg6$0qnnt=>N$w2p2a4L2*`>ZsfW?5N#mG@SCzJWlI@X^?~WWtZx^%nN&`6 ztg`jahK+{vQ>RQb<_0pK7>(wjBt3UGfyoQUVl4NG`eCl-kDv2dAMdaZnf~mysM?z1 zO?z=M&N(4yqMKZ~S@-s6%bjzA-LTWYM9+`XSZRGHqzA(ZR9skT2x0f0a41whcwCY# z?pdcreS_P6#Nj}rW@sqe=v3y_NaN?#(cxg^8}Yrde)er4<0dbEFkSW`DS7mBB-i)U-Ei2O`&zsFb z7Wj<09`e29?flTJ;+-qsRJpQv9;;c&t2lkXiG8!o1n+6F2@OkcE1?9`m#3RIO} zRkTH0UcLZLQ9skA;@;o|o)0f?H{+H_-@&hT-p2=oOYp0bZb3TX9c4~elVm~9R^QLj zu)e{2kBT1^5@BJ};~=2`Y#U-aVoBj%n~cMtl7n-Mc@puD+iM1h2V-g9bWthkGIr71*- z{J1%XcD*My6G69<9^nKT7}b<0(Eq@1L$#4j>Rop}KU6wm~dE6 zkjPox)nUu+jIDu}kdF}{@AQbN>g&3yZiZ@*B9x_)L2zAXs7*ouU0yV%{T}7%NpSHN2Kj-nguH=(G=&g_{Ttc*fwr5A;1{r_&o58zlUz zH#aU^Wss52C5Kml(~5h5TH>9_pre5C&D0Ds4f+qcpmEQk(c4A&y+EVW{=J^;Ga-g2 zh)$frsWOU}@6K+jt}Y8)JPlie9q z=|9`(OP`Fjl`29tbUDv?-j2;P1*Nnz88Z8b+zd3BVqFIseSj3#8T$dHwSz}9}P@!RN zFV{HBZzmymur7!U5`n&+UhTX0v)-B z`l8%EGS6pw-zw))2`Q!k#8Z$M88Gvks9Tlp@7><}86R}SrzlTPO^F@$S*NG&4PO`J$uF8AeG z3)Jx;tOKhZZa;2-vZ$tCkN3a4p|$!`PoaB8JyRl#^aJW)B~cW~Q!BzKMy=e|7;cY< z!!Fu@6FzMr$C#(q&{JO$+;8!$Qy%&U?;DE*v^xeOhx*!VHYyzB(ZkowziuirG;vvu zJ!}g}F6H4sbChiF8m=_jwW)VMQ$@M$dCpn^AvihF_Q2X6&*UfO$Tx*O9HIjZLg2VP zN&Il9jlf?08GJPuqyscKbLTgBFrc1Iqh{w<9R{)_DS96{4Ya9L!(w!v?|=$onn-=THFIyBTIW zqSz?RVV_MlF-&DV@I90wjTPr{P-5NTx8&)MVeE#Sc~ba$z6K|6%T%0Khe`@g_X;n4 zEt`C6FM;mm*=#!{M845`rgQgT&jv(=0TcdCL3#dph0=T4~1J|mEYw1=O%}vM=Px=RSsh; z#UN#yj@!RnQAo|-N>6^Zu<47x@7}WODVua57Rd}}J$K2^^(8(^^z<%h*rSl%TT#`b zv8tY15vlVMcPuDfcvQr<^H8aI39fnzbqDQgX?teV+vW1ICuH-hPBWqZ#y|~On)s1B zd4tD=##zlSac^SNjT022Q`#odbQ8Rp#y(Ck8UrT&Dh3a~o<#up+dT zwiGN;scNeqP!1@sb7nx}i`@4f!8ci_4L7$zW^p}kSmm4R$=;$DG78NGz2I3FEo`$h zq7tiay~#{JP?fUUt!6+~8NJu59TX1E9q}TH4rMvE$16;YVDe?gH~Sn%E8Phkwx_du zt1Muc1)3+9?uKsOxX3+mQ&rv>)nLl=(5Tt?)oM0*0a8#^IrK|r=Xu)c#))2;sxz#f zjrCR-ZR4A=K`;^~U#spO?wie-qK~k8gup_Jcu1-NTnFN-xC#PBy!(hA%RkM%7Y?Gj z*I!dffb#ESPX9(3fZTY-=aSba{~G)J6_Qa{A-l;Xi@}NELp{$4dWC~G)FF|d{}OGo zq{U^fw>^3YbhC`t)+8wQn!P?4O_oR28gymBBx2cWR$bheryI`bRnxqA6P{UPNuRq{&zz{;KMFPFT<)PADl8}+9a*L$c7m6w#}M3$^(f37qO%A7W_Qc~G@wK)j&pqI{ z%IjP&Hr-In57Ab_TbIkBvUCyM5kKrc4?0>!C7nGP9LxR&w zrMrn;s^3+U!*dFKduT*ms;{0>f5MxvYbZ!8bKIub7Mkf(0RwwxqZoY)EOhL9|I+UO z-BS}_?6n{I<7a-{=%bwT8`dGzvV>p}%)%|qApRM^8>)N0(D7l$Z;@jUMHuHnJg@#O}Uu#u{! zD~}+TyK%Y284Ws^drY?<8FnXpEO~ezHb^FDfh-lxhV6#+hkTN|CsF5?R(vSEqHy9% ze(ffY`(TrS-ki7ucNuh}~^FAnE(*VeS;Q}_k6pC|_sccP+Qv+H=57zh< zAcA2G^oNyfi%^i;`G*#iC1`<#i@m$(8dpNpLaoI=^p9Zi?22wSH#Z$I7d?7-p)%OH zh!Fbu7M2c6RgsMt$e7oRE0z? z@#+k%mwZWRPnk1`N@rY4lQgNt|E0E5@+`}&1cg$PuL@4Y)6w;j@xJJ>$>LGl;MItIfl*2xL zKD2>Q4R|+xPA=f)linsL_>^+U^h8v^MT%*noN^s~?uOIytzL^4kBT^)dqDj; zQEo-e`ME8=sQ=DPAGV9Oye7&lFdSxh>%LCI!*Ck*q66oXJ;>_@2QmzNW3Ssqs7lN zu7_LVBg~uqIl5CtNH)|sJo;;l?F55NO;0VITVBd)Kv{lrnU3Ee<2zUD=r2w7INzNY zf9J4Y@Qc&tJB13=NNab!6J{F95L2o??Rl7hLdfA#f0|aH;(OW|i(zA~kY;(P06tf?g7N39*;C-7DRP2k;pN zGw1CwcC+Wsn1hbnDlHue?<}GwILx&aUlD}f6MhUxcBpgchmcH zF9~PbGK0Q0pxQhXK3<`B3zzQl#pW3v(s->o9hhgFbxL#drXzCZI z(+be_iC6|U!Jy@gR#LWV7LNjrvC$t(jXnV89$e@@j)GCbF{m?CfxIIVw+q4DwUL)c z7G#icZFjA0L$_zDA4Zak&NW58B?BRHP6x=D`a#YL$syKN{M1gU&CSK>}{0 zH_nyDs-zkgH%|}Ay@70OUg+vt7eEg5 ztKQ_hiptjYj4SSf(#&($-mo6-rBW6*!PR+JW({=yb^vNY9`e4P(3N(3^vH;c<>1Wi z$S08>ec)MgXWPqlz8D5^OUy6SkMK8DM%9~CJwed`vCHAgI~V!2<;DKk6N%yyAYa=$ zH{=0=f&MIe+rg8@3sgN2_GIbJ2k$l*xD~8l6&|jaDYTvpoOE&E(ppYchP%jjmRQ>^ z%^b8^S0lLhzkuFsHMoYsnk97Cl+|$*i0IFw)Ix0k<24lad9T8&4zyuV?;aL38n`L# zq3p2fOPNHv1yF$+nO0iCBftqAl0U^nP$G}b&2nXoE!T$|ScVH`kWU6S{O4|M+OzW& zsX2zRps=VvzugLbs8o{$G6bOt8D>gBZO8fsCy#2~oFSZ=kva<)Klj9p+<|^fy(*m6 z>Kp4R|A~axw(OhH)(XPPuScJkaU1h?Y#pcr?%n@bsO5FE_?b5Nu13mBhL^mhD54al zK=&hSXVy#LLnx0Vo47^6DPf)5%f-{<0hwhFNC^PysRROMkYYq4(zJ^acE9#B;Tpms^Q&L#_go1uBl)_EekLCt_rv z0%Zuh;>=C>a}-%|-}-yr?6au`SL~12XP0EDA;y@-v8cr*RDMc}%A9&Bu+qGT=#idJ zWQH!W!eo<@&l4J)I?(MIVOMM>f`(ngPye4!`4DwNlr0nXbI!P)?M zuiE`x4w?Zf{2@V_s%J;hD#wAiH0ZqcX6d~|I%lV~0TUtPqa%e=3V6Jk>E-5QrNsSY z$9$vQOVN$V3)-zu%j%a8OrrMUBCHC`ouvG@Ewjf{U{okM(Uq%Dv*`}t8Zq_Mm+iQ#7E0>gLTUC z*RdjKREVkVJG~nZS(GZem|kO-V2HzivUb)*3cAPhhIM$?itP31`=!Z|k7g2PI-JLFzm<+fCzOoS?uLz#4yWTgTWXwK&saqK3SA3s zuy!@2q{@v@{!5~710KB(Xr6CC?J1XeFLRif0}5sNmDFT~W;$HRm6xP@lIe6}Q={^D zyu`MuR=ZI}BhBfa&s_q1ZSCn$mS*BAz}U1fNz=|hMyPt-WZYR<#CYv-e50>i%1><2 z5FxWF>&Wf6jU{CSdvoP+B!{wV;VL5*^D|X;^UxvTuBhC24IaN5qhbqoz6RN*baa*D zllbKzF9}x|(+nW5ojs0{1Vs)Xy5;(!Fc?Ep5VAq7M_cTKv0tbwoLR2q z#?eI);<{9qZPQxs)fF48Nj*!#qn_Sa4*``<5{`H1LC32d#=z9T6eUf;z+I$)ARh`T z;%D?s66eeO>w&i0({-+nW4ZnKeXn4_pNTV@ySI6n$HhFoc90*zjnF-gKLKu8#bg-s zOCJf0>-Gu@vdRSXMs{Qe2Xc;%g07loz1?c*0~W>J^B&c77rf-ur<>KnzH9@v`u7d% z=G){YI+P-1a3rog61fchp6mOT+n0WLwbgX-tp3$b%Uih|$qyn9D+(jh zBE>H+_?NIuYxyh8n=U`-53TI-K51~Zk9_2d!3znPnywZ2DU@;c`l{GHQ7_xQnr^CS zOQ$8B*vVF2y>yBFQUjuV)q9jQ*_Ic1v^JbOmmuhfceHc9x!n-r-&mxcmx>k>#i%G# zE}V6gaV6KDl%8_`*_rN{OV^5IcI<^1b1za6(S>72dG5Td|A=Yi`RTf)>SE7ZgIy>d zhHQn4BZ;GvVzjI0<1QdQouR&8X%LRJsVP}gs;d@qxW)ebXb?0QWWHOKGVpXEFE<4l zmk^Dq5|5TF+LU~+9(DHYnC5iO%I#Z;BP@~qYuTWCYpAMssCiuViYbfo2artD^y+Zz z=7p2uq#*7S0Z;iWfQaiG8FzOj4k8o5QwJtj1YO)^0&&5@lST?yRUN2I1NwKA4*@(~wFGpPebD)l%%WF_QrlU}qz*hWLp*rL^3NPoAR$aiD#jC|N zC05%?tE1hK$gVGGuw`1G(W=R8B`U)tt0P^@l$*(e1T5`IGoIlV`v#p+BDZ@OJYi2Z zHxD2ona9lnr8YAUPo7C*5$zd6#yrns4s=R|qBh59c9UGS(KFyn)oyX#VZg1odHd6p2rJe{H_@g`!Nv$Ji}y`}gfz88Xy@1<{rd?x6v6n>RN>EuY! zuciMJ>ut@guv(E#Tlkv&UMopamuV5rK4D9rAbDs=KqPC|Qg@tzcl@crLCh{~M5b54 z-Sx(By4QV`y;?3Y44;UR;{{o&HPS5REw8|Z6_GxzswDFpGPg4sD6e3ARV_LRBeZw! zog|NIRz0!F%y6%Zs%_T;b)5+ZBu~FHVm!miJ?p<%T@a8r@LK=q;U%@snJB~2U~l>% z&v`uW)?HE5k8iSlxIHVwtCFXhiqtNu+G=b)Pc>-d)pgQl`ClgAE%4QAOrUT-MODLw zH66h}D{e^MDh1c?{xM#QjQVeGFGl&%nztz?WCMs<_NG%t)-kR+@fXviuQ zb@`y(ADxOB0p{@HqOQF$iosJuTSNWDTyYj(O|r}377L(VzjVjWME6sD^x+QKGD+WJ z2`%X>3htSZk2e0%EfZ_Io{x5l&-Ckr2F>LmF^2_n)8%2Eo6%+M#wtB@xygq!mZq+Uh7P4CW;7ef zsK^aWB}X5|zWtE{1=l};4Q|?x9Y`k~HFWy)Or}Z8L#fnzW9lrt`ibeW`9{UBpQ%)P z4G?>yo?3X?J_wNH*&32x1mH8hJLI2VS0706Fz;V`Ha!TsU1WV@;OktSAQ`jZOYlp2 z341#F{A91)wvYcw%|1SB{KjO-izK%J$L6*=`Dv>6LPK{Z%b~ON1J%K3sHns_pN%MN zeoXT#nZ2>JrEpftiXu|oS>6>V5BllVaIDV6zI6CQN@`G8jA}^S_uhwh)4}F@9j-+B zZb2^h)>>TCO}Q*2yr#8e;T>GKv|lz8U0t|#odiu_Hpaa0C(2)KY};7!^=fI=>nhoA zN;|fEGal?1s!gsTh&|a?D~#FCwrqvvJfWF(6%>v4XZ$HN=O1UBAT*x=Ym(kntosIw zL`6TsI%Y|UP3xB$Oh#o&cd4CeBZmnbcpf2tBk>=Sn)n>e7#$MeLEn&%-pG3bgwt=b z-NiS_DH6J@e~5QfA2L8TYclrBw*O5`(dzs!ec2zj1>;$;bvxiFr@_RuiFLNS_uVZ~ zXf~m)TLEsMbII`%-;U)9DBQ@ztnV#8`Nc2bc~&K2_5#8n^?4~s1hWlmwI;8=MnrEb zCCgQ>;IeQ|G!f~pXm1>ce0e}!Qi!?caCO~&%t*j$k7oJ)7&CB=O$sw#GP@SbUNUuG z*55LE_`#~7WF*uyffLx4ThAFENe=h7DGDqmE!#Fj0;OU1*Vsx|*84q9r>cJCCM zT!s>cd@sJ73j0b$UH#_kTjPQJpfLf@%jaxHLM$PT-|qV#VEqryzB;bS_3!^E z3W^ekzL z*n&=THf2Fad&vtjt9SRlM;kx$Go4!U-QNSX!gjv0K7aZu*y?QI!X(^-E3=o%tKkB+2P+_%HfJM}PYNcA^d(cy9;~ z>47brO3VH$l1Y7f@`_D~+7MBMyIyVekRxP{$v+Va;DfwWE zuf(tL+P)FfEMYOu^mO?{}>2(<<9@uQ~g)=CP}2 zo}Sy;0_&;~Wn`J5&3gvx3Zc7Jk)qhy2=U6px!LCmNb#zBV_(?{Zmb+4XhfLfR!|!E za@?Up_OIU}tl^V(jkWqr3iQa*n#nKf>~m9o@CoSlr0#t>8_#0--B$y7YKu`Jjj=oL z7X4z_b|_s(Ylq20c!r5IVx3;=%)W+pV<7#Pi1Ix&T4xkKeTT#qhI~PSpXyXaQklsyRfxz1QIMB&Ep? zxs1(=Cx;CaHEy-56Zq1r!ak!Kg|7IOdWiy=LZho2>vFF%78)C`jO3RmC-Gm2?XJtS z-koS<2*%;(n6_eqt4Q>(2slK4%604VmD+Qr6uEf`92rwJA!;b36Ct!#aE~G_E%>`@xXa*7q|75CLDWMhITm`q<*dnY-L;h@2H%nx3E@7fxNZDEop z;SIGvQ)`v~bVtKM2zpt(tPv8`>*bMxfLB6DFnddZo8M3844m-u@@G^6(i4;2NnR8| z%NkkkZaewLYn#g$@gl*2^_AyVbL{|xHTFq%@8iadO`$g7+cvZ5^yK+uWBGFr?V zDlIS;#PQc}y+mOMrNcs>XV9=vL$X^474-X<%fDm`{cC~T<_7wHDc#Xq(}riLgX`dy zF9`oGh}k5~-B*cxHdbw0S+_HPWuQ>mN#{Gr&izQu*r=v;?YD+gU73BuE(Hs|1S)ew zIfLOqDP_=dLB(EHq6jV4ozU2p(@|>I{}gcO^*sJ3~R$5^n9ku5h88g!oG0)^XYdF`nQ2F)e6{>@4 z6dSbR4y*wZMVNdX@1WiIjcWH9ruGz$kPBYy^}Sjy9(GZ0uahRYwUUKITBe-6ykGZx zC3Ci%L)u=#dDQgKjqQC{`wG0RsAD+8WZo__^qw?XTdIM`qu25U7nYJ;s|(>v_+!^^ z%nz#8YRh>xJgW?`nD}mg@AbIcC;vA7y&lES4hd#Y67Z}O6YEka-g{c4!UvLgx5`$g z#VRX0!bxzb)_Gy0(;qSHC%S9PyOJ^0OFM|TuSR~+iYf(0_jS{D-4kfeleD*hLA5#G zg{+G00~70I-d*3o&DANRmXL%Sx~0C%rVlCZPVAmB0bO;<;srGOBHzS*qwvm9P8h!& za^DPc&|kKHR>gC$FRGwVSeobJ<|gOeC4|GxJIU$8K{vc zpOh}3&;4AgU=(s1j^08~@T5fEbgYPz@CdA1Z&~Tt`jJC@nbyB;ZBi8^2tGdbA{Q~G zvdwf|QcZVhonDSTK$FylZZXuhzrW0zu@-bP-7$q{_50_BhjX5jco~h8*Dz-L&=E~(^6M{{e-QeG9Et?X!TkI2fmH)&T_C1_W#f?nWoZpg8Is(V=~QEHj0 zS1?bYbC^b$0!la~?yWeh_>K;a1~NC585MUgMmRQ;zFCOZQi7d0$>91S(Eirkru%`*B+4z~S{>7oA}< zRiirQ_Wb2QrTFrwZ^hDD~eI3r*=I3lr1WfgWL=PzmGsQG#l=uIk&YUaM$L z2HvL)VOp>dzx8-P_h&Z^JVrM2lR6~c6V(|7Ub^~{YKrnHS6J=E_31S*hA zoU8TWoJU1SN1PoTDIN z;4QaS)I$mx>*0qaGs_B7A-mZ;y^6pnSY%{HJ*x~?>LONWxbi5T4psen!iQ+ zZ2)RTE1SgkRHs&p|GXM9}T}!`rUf_n7W~$^w#Mnh1p$*;*PSQ*61P z{gp7u*)P&T8BSr-Hf{95L&XqPbgm0X(rjL}`t*byGvkIgYB15np1g)8Pu$uiW1+TY zdIy6uitV*;pNIFK4Mmk@GZ6bsGA3YIDu00oA7qMOoE!6YFqY(Al z?)ydR7Tw7_av!ep=S_Wa@_>MF`Y4h}eF%b#p{fDSqnMw1iWrAf@_zL^a;W|peN2C* z0d&yW7dZCc2+eywpHVEgNzsc^G$fj0#ia4!x$ku6JBO@|IuZ2}aRPc{(wsi8_)mhT zqWFH--zKT-c&Jv+qvU;MVi>g4UkW>Iyj)XkL>bY=R0k{V;aktk*^tGH&y!4J=ezEh zmTOZo25eO+>?b#b7rP4_Y6Zl; zYuvw+Jhbjj5d3f`mA?dIdac;6mWu6FI!LwG>U^aUV8q9K;8Si_2#fj{dT5K$z zIqid1hrdpQGwgrA(c&Z{YfC>W||>gmai|k#;aw0mSdIokbSs$wj)~I zxh_iTr^I31zR%ApT%v?rnQ(?m00*f8t!+KN3|pBNjzUWA#0w(TN7?Qx6ZNpINi(XyYXgsVpo<}iR_Uaw`Vs}9Dl3U;7TvAUo+ZkNFfQM|5oeyBh{>Dzv04ORq$R>cO7X@ ziAAsDLDC(YS!S&HUH9wt0-H!SVa=OHE&B;AhL(*ElV!5GCx!(a>+>iOE0SiOn5HVeLzIX;=G`)8rSxI#P4;cKf&P44>2QY01AI8r0I3|VUgFPOMF zY%}D-vk?oYQlKjS`cV({>h!S_=nqZP=I_$G1qb)hkD6aa*a$l1Uf8wY#=Mmz2}`o{ zyAHkBeI`$&R9w{mQEfAuI(x^WCQ^Y=cXIBX+T7~*o)x?VD$2Q;EdFtNX&--@aT}`^ zf5naUpS96%b7FI%c-=U#z804a%A-pUGBp({;V*>-pa*uAaj?r2H!E)L7Zcqi)6HSO zLVa3Zkq*_?!;ckAF&~LuVKIUsdg#;K6VBCaf4PFf>Ut$ruhlTQq^+8#Bw@k~XptK- z{7PBICoFA3CRwqSNs;v=&U*g+t zp)tM$vUk4Ltu^JHUBVvBYIJrw_#{yAn#eEp^AU1S-8p_1D&dDdyV5CcD46GSvKU07 zip#@}CL=52u109cRvgE7XKW<* z)IO?9=#W$*2BKjDf9TFUfJCktGr&aJb_NmCE4Mr`PYwqutCo{Td>Um8J-=W*Y!8n~ zo6lw!x9rxMW9RzinAR^1v9of<@`SHzzBc4^AE|8Em*k9Drfceoo7)i#5ux7ceh<45 zwP}7E-3~>mrU*P3$W)j!w4dMf?cZb5E?iAL964?4jL)&Z?kuq+R_dy-wmA(b)6d73 zTiI%c`oMRc<4wYEv~yaNH|{kdw3_>t5N8U<^%@P8bBr*JjYef5T4P)|b$AH%|g@ z*pWjXNZZ}|wr)GuQj(!0zy9+})H5l*wPI#bunT>b1~6s-s;koUB*vQmlg)#u#9Z;3 zF0m!D;)ybpo%l!5=H16d_@Kpd#r|)w%(mb#qj-+nTNU&c`39x&i$NpO2}85*c)UAD z>_rkScKxxU)h>EWbp<@C;ybTO6G04FC30ME%xQW+w&Wm&&_h{%&-lxb^&D18_Bf^V zatl}wwLLpp-rW1Jj<`}&Cf<~~m?tekG?`n)Z%&ijFs}*ag^%*olXjGcHGynHSFilv-{g7xAu_VtpjS^;Ueh-};Rw-T{hvyZfVQ|_}L z2Vo8$+0AWo68VEJD8+oS!w}MfXw!#s6PLp4IXXcu>(u>m`^Kpng?QBjvs|g=5)Gb4 z6V2THu21qTLvcd9&I zXi|)}mRTTmZw=W;3~_&a#w*UvM@=5evBNZpgOrL7Cfd&Jmh58;qi^L%DT+Mlovd}L3*zGB{V%p`wk0U@d zC0#S`0~>A@-7C_x*|GwQdpkvs6Y@KFY1LF*u34_dPDrp{`-IqNyZ+@fzlc+$nEu87 zWnW=yr#tHNlNN>n??c4%I6(vaJz5SrZbOTM5kAfWriSBTyR28oTrTj-f&gV8AP*# zRaMXsBW8JQ5T;eT3b4OsT^|hrxvA|z#et2Q(?^&?((*vjgEk(e{uepPWMYCOWLx12 zDUhBS46f({-jMW~p#8Yb%k<^Ug*(~KvhC5_rFWBrQCBWY7?-fv!z*5Ep1e1U;VNi> zmufpvKRHBc?9Zg89!3j0O@G>SOjXulqy&yxS%e-@ZXub7P>xjUO zQPWTbkTQ969$(I+`A1Cnfq{9h*OXfJcYck$hiahAdrdPG{Z&QfK zQh+XdeCN+!S-V_xNcyiA@br0NyWz4im??aO zE2bZ=F}7JaYD?Nh^=n)E-#icYzImDJ`(JyXleqVnUGH4_b@hU7vbT|V9TfYP1g{ziK4>7CwOYTd#^ zft*-^`I7FsePh%$s2fPYl@KbG!najB19?hzZD{5?(fD;aA!?Ce=VKns_wtjhH65dPq#Rj&4QjRBmTPZumZU~d$*H=ESaUvI@`B%tF+)<>1Ll6-PcWbLhF%uDu z%vyu<_GSnB-`#oDS=FQsg_jOcUPk`%_JfX1;4HRD?0HKX8htzY{LgK-q(;IXxw16` zvOyO-w5i8!AZ^`{*;~M~w!J%{yD{PD_bN{+eGA|-9Mt^>ptmRYZfe{~!L9b|CVO6+ zrF+$t&?q0z@3`V{yECST-&on;(#SfZQ!@R7Y5*83R?u2gilWEcXlC3H)~i(@@;1<# zpbU^^(cW&h+fSz&q_yMLH@Pg60w=W!bgU4yFhceznLxbnzyoWYBA@TMJz};xL!grR?Er zOo8o%4Z57#hD!z&YLSd3TK@TBHZkc6^y&|X9+?_8kAKz*89G#Be{<{IL<3VHv$+m5 z$b&!-KUibrL8Zks0aB%mr>}Fx$uf>L0iQ>q@ah<7GJ3i3^~^f70t?p0^x&&E>Snmb zb(OU~G_w)n>A+_w=bJ-ESw#c%Ir0QygvJJX%JNhF8!!H0wgPfr;oJCGp5P2x6zSQk zHXPg46Sl9L91MhYXh+5GzH7WHrcq+nKI>pI?{~2C!bgLvYCMH>4tGY@NBLk2!^t;? z5HFKVuNZ8aA1RnHZw}<%SaED@pKxTQqo{;_yp=YpInk`nGJvSm+F3C^sfFsxxedn} zq&usqR$#mFJ$>vH^rE;ckG{hmqh+%T%%Xv%WWH%Yxp~F z7}ixK!y9O~loQy@<`#hC*m-lsZ~*dbyKh=C%3Y$t5HssrvNyPv{{b}rF>GDK=6;?f zrLa-(-}e%W-m9e&rPp=Dz4IvR%!N?YIwS`Y4eB4R5{5Oty7pADTy<2;wYdhK90%)Q!k-Ms{*KGl9OEXoygh%oAX8s&Y` zs9Y+nH=!sk@P?Z(sJo9rajE$gxqwYHSJ7s#=47}6Oz{?)QvMR88r1h%eiZMr(DgM+ z04kqbmOY74_n*(Sb@J5T4BgJwS~)kpD|jK(za?!1Sr`M;>5ZT>imV#hIv3}979id4 z4x5@ z^Gmp|zPcMq%en0l*;wIGB6<&#<+55i0G~^)I>`VI3y;>g`d_n!*Lxv3TQ5$s%Jh#@<5wQ(C|TqmBrloAO=;jG<9_J< zMQAylN0eJm)rcQsDvpi4pqwI41V$`wEDB6vWDT`Q0X=!E6*$%ORBUwp#F^rNZwhTlSgqMTqSywGs@i8Zf`=|$1V?Y+2PyQ%aMD~{jj$WEU7{yT~9j^HaZ^&LFeBCwjGrg)mXdz#^k$CKoh?g zyhk=5P}zKJBg(?heu6JT>h(rKZZudlQN#*52r_0@t6joHcM|Sdj+E63+;(?8JS7ve zw{&pMH2rVmd&Lc+e7oyeKKe(LF{_Uz?|NXD;$rKX@S=}7$-R8EU5fezU zEVJGZafi`f%hQDM)Z+IStG{mEHk_=wXJ;j$kRVWQd#m)+i8EjzZ?J!Xgh1-x2B627r=RYKsLb{f^u|#uth;YOOw>VPNXQ$f?S)S& z3+HjX-5$kRE4npm>H+1V<1q{eeeG@W{43_*B}sJ=AvuX6g| zMqZ_Q5+stc*gqKmIthMU0B(fJo%mmG{OzF=CpwG>8Y{W6^gBd_xdeRvVZ}`X%io57 zw9RD7iN@h#rr*(oFnbe?1LK1KlfSQ+qszf~rElJ`I5b>>da9;tze$&xmG->*ybXN6 zGh*uFx>!x0WW0IJv`s*AAO94x?T2PX5)V|PA4N`X&I)<6hQO>e_toZiC*O$T8dw{ zKYA2L7yNBC{mbZ6)4&>7^whcp>RNw{fO-ea(sg7cHjpLN2B`3b)MVc)DibtNWA{%CiV|f2gbSC3n654^d0}Z`S|np)BYf#wbPWSNO|Ju zi%w~R6DC_U|395D|2nY0W;_^8+}J^4F;T`RbZB_=&UL16O{nMFZmT1?O$9`ajUsJ9xE2|y{ZqCMxoX|fVS|=E9q&MR z^;v3XHYY3DTk^w)<|?KWA5!k$ny5TvmJ2;#11;y#fQeP%r_5v(t9Ocw_yIMy z=&NI;@<1ly+ME+;$zVz0w_&MtK!$5^C&-6u8-9rNZ5~u`y(I0~az$^VV8Xo(gi4BE zPn=FS4bu9|zp3Mao#(!M-zxh(y%@rDXFi0J6|lZCc6z$_ot{*MSBksfyrz>MhSGD5 zl~}m*YzX;nE^F@8S=*+pOrA;LE97ykTd#qH@g4#Rvra)|PjrF4M_V-a1gmlCiSWD9 z-hj(5%gmD}X|M;`1%g%cr4rf_Ypj-#*U!jwr5LS&EI(~fioD$`zW2VdyK6&a$|E~z zPiKdiUe`?cup$3mE?pnKMI++Q#Z;j4>feul4oT+lm7~Q>?RlTLsjn`?rTzPs^Cx@s zY@tw0tLhWDKUn`}*Ns+Vw za?i5(E9@$EnC`AUk*UgFm1Z5!(TemZdjR%dfYU`G(tls2p4le^>?XM$Xs+CEO=R~_ zX^-Pg5Ix*?ah`5s**VxNFM;%iS`e_{$m)2Q?aD)rFu=V$S z3QPbT-1gB_i%50yi)|~#1r7a=69R9!DS`s{PMMmJLgLLZ&0Egz&R!93;euPvCyouy zf@%yu2F2u2<5-)r)<6?{7N#>)<~UXp(3LD^)DeB_a$#=66JC1nUkB^a;{zLdja`y? zAmwc5(bM)PQzAZ5H*q2Q|L{bcPTqc6ck?wl^ruE3PE!^&->rYo_$N??g}ms`*4k9J z9>JB0gukIQF37&rOaM>~X(8FS7b3;$Yo_{z%x4x^|5$WC@^!K4U@N75o-9bvRwC-j zlqWbgByrnMxP{5Qq3HmP8O`MdB9F$(l|*jorpA^Mi2nN^2fwn8THbbd9Dld2WpCsy z?eDMH_;L5mH)8%MymILj>BRHdnj)we2DJIC(8*|5B)Z`%uPXCBQN1Vd5#KG~FbkV{ z|BHKkO&Zt>vzr5Czw8BpXfF<3zMVRHJpVWXfwhr)w)XMdJ&>!$HmJ9bsDTD4%Ow0G zq;G&Z5o}*o<~>YR72Zpm~oa##-TA)->u5(CzFgYoo0#%KEdg#vY}FilkWpMpnx)(N#z} zFc@UB{9v~+q^{~+=D{=p7?tzy)^k`7riTOQETjzU>jJRsx~1*`S4G?>-?JOkc-&B4 zjw~@-@)*c|e&!9GU}3&~Z5O1J8dJV8^?c>3^1jVmJ7mLPRTQ`WKp6z&+2`DBMIGSz zy5dD!_-wn%tCfz24`|pP-ONxtpko}Q*xZIYj?TX4RtS$_#gbw4TMsmX2@rgNI1oMV zeLwd-hDM>~EXGS`akH#@9LDHTVy3{VG>@N)vrInS@2GQT$RIBny=UE+DCVLV!< zqr0#Kuqk^}xc!|oBMlyHm`0`ukTb_AAe;l-s%g%saejrU zd#}CNmUwSKdR|)O{aNIs=np`oNbDCW`R>epO5DS$D#SATr>i7MAv|X`sqO3O09Wsj z9b_42?X{CZH)p?6oiya_Fb=PuGHl*nDOk5YD3?6=I4n5TdkXI|1t&OV;bXu{JL>Q*Mz_UX29mZsYruK%7Q8_-$GbW$eFslEE6lK?>_ou>9qBmVw;Q zWqVZ$lK&J^iJs(h3g=WcK5uw79b^wc}71c9Bp&!;oIgM!LxK|h5e_9E)3 z7+LSK*YwBi~vkFFv0KX``y@{IY&NYlT8ZTSn(v$5Iv*vFy zmfq868Jk6a|J;KC@Z=%KQ5oMoR46qnUeNZ2X28p4`>hT@o!+r_&Zy(#=j$k0Mwm^y z7P_5sVM)kqf?hu~nJ}5hD*Lw5tb{gyuumtWga47|$dqJ286dB6;i2(JsdhFO{GuI7 zI+F16E-)~rCXxc$r1ljAEm{#5wqS}M%W+EcRTz|gy`^HV_$s!1FfK4PY+ zFin=|a;q`J`7Q(I@9*fM0Mlil4#v@+G-lAU%|Z*J9aL7?Z)tY$k}1J9Q*n-bpyd0) z7RQprvur>aF*50r*Jwm@Z7qvpO7j{VW^ns?!KW-0U=9ZrZc5HE!an>{NNZ)Slx{zErJm8ueVu7ihntde+z1uorwmikiGs_LZqJ<#<_~|zCZI{P1B#|dyS?~QBzjp zwtckCM|l!iV`X~kfm?ymo4X#uF7x>pZfbO$_OSMxCA`1x9nOW*7VKt6 ze0UIGwa`Pb=7=AI_9XC1m&K>5(7*5R@Kn$AwMW>xHAQM|D-$1yVx8x60K)pA7+tui zV_w0*!1gFsvO@3JW07oluKD?#eQU2l#6hv!1Z9p+P7Ps1Bk|p#l;~KIZ|P|GTig z^MVm1xsjO_JLEpIs}ic{M7Bpj!GxThPrz+M#|xfoVWX-iq{*2*9uX+Ksi#x6-AJB@ zz=tq=9B`-iR)^ye5V!`*5MFpm2u_}~dytmO^j2$Cf0LjG5xfV`iY}8|$7@w56k_tC zw4{cY1Kk_vI-|n3P@{E!iitmBJ-R1)5>YQ8Hv(h;>Q z+NXdyPw^9t*i0*~NTIFi5uwh3hm*STPZvgrcW&y=H}sJE=}3CxmpMX3X`U_(@s;@k zGSX(RgRwnV2{>+7lSJg3N0xtETU{&e(nTI!^sA6^N0Dy@wBjhpBk3CYk#hDuL|JQU zYpj^u#cHpa%tZ_*r1lF5L(T6LT|wxw=lQ~Z!2_xH^ptzqI=biQ`>A`2 zSO|}@A651{DRgR~lqFS=j>wva$zJo98==-$Ampmd0}QJJ94`QD`FU<5L#5Qi>U^7z z!u<9FcVw(Ml}3Enp1~`7=~BP2fVRS)vbUa;ygbcplRe*gSNaA~0;L_uqRqWSL(Kua zuWK(uX`UEZ3t;u))C2Ur_igT>JAcq{YOT31kLG*nx5|(Rt&AMdjk;iva34TO`-ryd zPdJ%qd{u8);Ux!6v!Q3%kb!3@>-1$ICdC*Y`0E z?7Eugk)VZTOogPF>EbQp`OTmY1<=}yY%enWpHgH&`^E0Z3RsTto!@q*-;28}=o^k( z9Y*FGRGWOhQStJvFwk64im$X|$1d;)RL~a$X70KFx*=&sFv z$l|+INRJU`!K9$c_HPUOW2g$dF^kuSHu04bc1Cn2^;0UGxXl%b`!d6dwH>)0CnX^w z&|xRHj-kt4si3`Eh@}<;xDX};cB@n+27+V)qRbJ#BnP#I^(0|#%lraA(l)^ zE1igkMyQXE-&uqZ(fqo!*0vo1PoYVY|8oxUYOq^Zr1^ab+*f(?UI}( zvs$w%{mYGHKC^6N=>lOvKQw$}(xum%@45EZm9eza)52)hoD(l0*UB+%c| zVNN;kTq2kV&{s=C)wQ|}ZdjWv#RL)RYOg_#H#_^-Ew&QBL!OQ2>m~Eh&o6h<{Tdm2 zgp>N8nSx+bxk)|1Zfh2;&WWYvR%4zftxh3JL~kM^_mKMWw8k8#9ZlfU0#rr zfsvqkd?{sbQ19T8@Yy8SxTGgbJIWElQ8|xuTXUl1+y-(p^rreLOP228p__vU`E14!OMAi&ou%{(F^e~%2mskBKh7~dt2p92AM2%iHD>Wds}EWpiF$WzfAG5 zeOAY(J+D++2mV)C5gyt7=yYgM;XTlJ%)*7M8Cj`y&G|V{t*#FoVqxbY9o;IcoSf{u z&kvHWU8laRi`VHzjJViM-cYZ1!?m%f{Du(!4e!zg<*CMWyV*tyMZEx>{O^wA&XBln zG_**akzxFuyWqlpt@GsQkBtYJ(+f#cm>vVj4da(|i9BbDVzB?aojvydEGwqTwdLP4ftY^j-Y4TsnSB_i5`}bu`}MdWx7=5l!kyV zkN}Jy?Ut%@M~@Gd^%H_D0f|HXSWm9uB@^DtP+CLsVne#o!Ws5QTh)ei<9mH~$0KSn zQF$Yy?~=5|RK4xzyN!l)=abvR@;>TH*lvm9O&YNk^;<$d-(n{KAyK)~W(3v|cTHWj;7mSTWRPNN$SP5!{b$h(lB%tXt1J~c$_qQQdg0Mc(u4CAX}rN39bxH7gPz^$7*U|+uB zq2hyzF+Yk#|DFX7V{ck$zup_3e3WbRU*wW}-DY)J-Td*tT@T)qls^_~^ZuQsQuqzn zE4vHRG@SV?R|Flx_-)~x2&hE+7m}c)Wjl8|;4VaGD$~bT9^}F`3k5s@AbFUuV63zse(JwRFCGHy%PvBgTP#8vM25ye~Td;Rj0f z>fcob`)oWL*b44vsgIZCnC}j)TO5Eyn>h$aGo{kBY;gR##+*x&8FIlL_6_4TF|V~U zxVW?nPQ?q`vkgwgqy+)h&M#Q>ft&AY6)asFbL{69d7fi|aE>Nf1iPR5qJ-RL_)L$Z*I*6+O~R^uVR_rtDz*(0{#0tkUKq_{N?ZAwhZ+u|8_tdYIW z)6*=Wo4Xc&wpWx+7G8=0NZVpg{u)6~PFZj4h_-p>$uk#~A}s8s5~XWZD^qG!lRUJG z^#3FnX{04O(cYLrUq5!Z|JHMM+H0u0+mPYqIL*9ae%f0!X3juL2U<*`!;)e}9yCKG%^`TVgqZGC!DhQ7 z2J;&Rp%6^7uj6Z|`ShnBKl5mEr&79fb zEmrT)%(jVtHE)GCZbVqWZfmP)&Hq%Ju83{89Ib@`X}J$#GNIagWBChuz11pP^-GRi z4l75k#p2SCEt@nJX*u1)5Z7_rP2{RjiTp@c+zrT9{>DDGS7_zmvnayHIAk6saf|&b z`}Zpl-C^M??@#^*cleZSQ*I5bd54w&Hz~y;D=@UDGs+J&TMPPh9uEsU&$jhbhwyzf z*QDirPzE|F-TMk$S_RZ$o^5e~4~w~PuSLr1P*=Xt^{x+elp4er>j>Rr;i$<76I zT2MPDmBx>%~l91<`T+P#O}TE5Cv(Amr(7L&f^%AHU*pY^y6kH;i&@2bkh6mQ2rLiz*ZngPB%-Sa*i`sXAh0? zKq{{YQd=9TGBRv?%`{LF_`*c0Da(4Z&&t>w0%4_?+f&|gF15g7zd3h3@b*Oy9edPr z291QTXzAph+)*-ke}S@Ez-IER=ykx|&k2A-SVUJ{BXBs(JSBqSQb3v{T{)to3%S$) zMR)0qHkb;=-8Ieh43d~a0ny6a)mYM?;3*(}Q!(tjx{?K|WNHOJZlLT@s!QOo-{>TAITBZR%pJMi?1f3;-6!XT^m#8RpE z=xma7C6+pqdPq(GEeS_7fl}xCrj6$Fy&ma2$-8T#+0vIugs62Fe45_0g{S-M45(a6 zGs##k0TFy@PGErZTo)Ut$;H#&dF!ZY0Fj~Rv*YNDhD8#W3Sbq;Rca>vqFE(%C87{} z3a+b3TV9ijkAyYJrP4O&@!4`cctG226N-9jobkE&Vdpf<^+ySyNJqttWBK}GX=Kh1@eMLu96^-9|`zuy%BVUD~G(f-USOYW*_v&JLW(>ED_k_KcbFwCDu_8=>zTi*dfKtNyrSq(y4qzdkPn~KI#@ok{4>+4k zat$r+K=J5d&4DaPD<;!?yorhXvO|%eW^+$L7Bsm-A^QG z#}SSe`^*R`jz%K(AUcY*hJemR%dyBDqrJ%nr?BwM5ZY0f5&h46mLi;sKe(8LY!Y=1 z3#C4mc0uMry#xt_?l~q$L+%cHqz~GM0w@ZVTR%}|+oqu^}h0?7& zQg-vbty4vMA>I}cPRV7%)w_lf~h=e#iP^u0Z(?S(6$IB%E zAxn`JV!wQGk8hgkp#A13POmhJxDZ3}E1=|(bl0H4XADyACE@$kEUWvo^dZ5oh{<`Up!1MY!FsJ90=m36 z>_y(w0b7{sv{=7{a$6A;p4nb+g|dv;t`&ml*wI$r4Le`ZvkTnz`xBtl-=*u&yT8$S z%#tugDKl=&TP^``mk{}$m1X{w#Nuigm7lQ~q`3_kDl6>(X;vl8nu3{izG9d^+X|zr&BKF$}3g0>&rPS0Sva{%yxdf~tc|=J}cJkO{)KAsd!gLHvk@ z!)=N2N$Metr)f7*uVkqnj*R*CCf75rY>HNbWO_c_GR82HL9AvstUjlsP8>_q~}o!F*RfGS^*~` z9tM%uXXS0zCMn;oKz}4F#uV6X>3=pUpFmJ9XaA6$NKrk&M%|a!i|$ zbz>fAaNHChu&l$UH_~m6ZVLVM?HQZcIb&Jlcj!fSO}_&D?1K@>3?kydVGt1P^f08C zPmCSwndcrKd*}IYHS*wVMB{iu=~s)cB;Wbq&;IhZ;osiS$n?@gAN%l@X5pAr|Ji?c zozReDoIY&z-c)y5!+>{_W003?)|04^?1vT-a@`IFErU-2DX*ZeF8q14_Uwhei-{ua z`GsA$g$Va2K-!6A1+AM8D=?$C%2#~YVt9=1+UIHKaVaP8@nQWA36*sbx8MEcL+F3L zQY^)6a#Ct`%rYemQD377 zB)9?5+33?V58KpL#moh$@*FuIbBIAUV`kftkwT>hB7R#9fE?wqD^je+Biw|Eu9$Am zXZXi2wUIQOl3attd$0+AmI^j=$@2JL1lEx4#@SOHcTG@fULh+(zf;w;=p z`+UPiv?(FQUIs%yQCJ2+9(BBcg^QFThrSI(`_pe^MtD6=I(=J=)5jAk(jO0 z`Qclt0$Wmy>QL-jND-XTuW^0tX5b;XLW;xOI(cT6AG`n0T+tu7fMEJ#;;M}QKi$QW z%)cG;xH(|tLc#LklDH%SP+x_z0lTd~UXJ<6HTXE0p>Oc@)*f)B#}B@Kf2UUS$eg_` zy^}BBjEr-WaEfy%npe*0u^LjJw(f@GL8z<1w@84667v1|>huLtn&3&0C-6~Ats4wQ z>$5`+x7N4GWqSVXk+aL=1x<2MF-E@aT!W^0fZ+8!bNQ7q!Wd?=Dv)x?@+2!$Io+GU zxVL_4h~{DY)GrwzbP75(D8#TGS3M}1?!H1vScKrKaP_29nW{<50FKySX|X{!QVN%| zU{>3EdN9S2gZ%Vns=gQgXPaAsn|Gm7WbWc~ikjXC$brMjYy4NeTgaEk@X?hnN2UAL zi}BB8VA5GGOuXknES4ZbA!8G(9MGawuFsT4Zit&({LCh^n)jtAsW!uAv!;iDn#u%y zCaD#wqU*2l9R0s}=&y`f1{F*56=KYMwo^|Y*Q z?RTZM(t@>4QIFVuc;7E7uI=y;R(2a^D|z_XOb zXLoBkvEzA`bUWFLK>)0Z zwwQ$hCi(pb%m3Hfb;nb^#{W{1qL7iTGAbh5HP0<&Q^{Us?~&})sau^8A(`PyviC@K zI7T8PhjWZLGP1Jg;rE<-eY?MV9k=WE`uWTEoag&IpYi^T=ktv7aMwh6|KUkA?v--n zMIBlm{h>D92Y$N3nW|IYPNl{6kQXL~KRP}2DS;OSQ(m5C{%VtcsT&-;eXaR1t^MtF zseA>?+ZXH{LF83Gb?t!Q^f^%6ZZA?fiZ9+Q8w+lAY{tJfD9ys}t{W*oG&?ua$N_v% zXo9ti%3Jnluq6A8!AMYae|%VHd?{F4<6L3dEwEYe>jZsuIQz$ATR47DZ63$C<($x; z&q_`nL`wURH1>KN?Tew$ZVKm?*GRwr)g)MIBv*A{EK=NMeEMcerx`;ihyjJ{?t{ds zOgFiE;qv4%R?kw6ALhNV5u9p|dM_@gdfCSOu?A(f+W?%!qywBA%_=cV9(^zM@N==| ztxiR^ic4?MYSqVO_;1%$l$R>pPA4*C3)8&L1Xhqpk?$}Q9=52ghjO3Q4gA2yD66)# z2O0V$=stZ#@3~yk3#rAbn4%1)OA7b|>PU#L)D7<55-tg**OWnx!-mqzLafWN4y)}F678X^Prl#wqvQhTMd}|Hh2giB?R9t%3Tx=B9 z$au7UHtZ0D30ajyM9YC-xQ5;P3}kNFvEBbMPHtH9U76o zQx0A@a4%)%sFjQbBl#N5X3o9mJhQn;UVQGc;DU-rqb&LLiThQaBJ-Hfu*|gOfoAAkwQo8Z z+LTrcItJ;Alh|pE|8LAU%Xck_|2uELRO)U#MgwVlj`HE^1cgOxi75DViT()=nN4K zI$U$~C+GS#AJ~FG8xqNHq8rX-^!y~hvAbxA#f*#oo7Pz2b-&fuwdR4#wikU}GfX-s z^lD_mK0lsj=d^14Z?y+#w*GN#)k>S%a!5tD)|g`b);eoFyM3$}r|max7~>f1v?ueU zuC4O2V+)&~oRc+lYSuSOJm!-@#x~RCvR+mjKqp#od7)&ww?yVjJiS6#1=XkW$?0L$ z<*Dfpaj09vGk#3PX?oJUjTxg_?pY@?Z=|%&2So5H#CGRqj(Xf`<&rw)v-A?|AUn~i z3hF9SvDb{YHs<-}c>`IL^b+=PMk_({1z`CZi58AZvE|1@u&CV5FLwIZUAEd!kz_}6nMdaju0+izS z3w#GBrP?EoeE3oECsD(1r3HcZGz3X}vwx%nJC8m5tp)rs{)EA0KhllLa*3zKX&KA= zHtFtDJ$T1v`5-Ydip=`C|9!D=^A`VPZzc+UIqFM?oG&%ho+BnXNc_0!X6GGRez{Mw zZA!{F63(TjJkh@*V|gQ@u*_?~N0Mxmsig<&Rw?F{IjS>3U$KR|Pq!g`d>_%l!xU_= zgi8kxp5{*aRHSfk-~K;8`o}*)WmQkH_D^E$qbd5{O)*6Tp6vR5A{tJ(^^N^-d6|RT z{lLr)AC}d;`f@6iaAW-V{}^oh6Eki$3Z0_Yh5S%YH2dKV=b7wxf8!5kc6OG~3E0E$ z4N}_vE+qz(zx#U2z)>o~?Cwg_mD7MG_J=uS5KRY;9+nlkm@`Pa>npnvb({F$X~r(p z*!K5uV@e7H&kIFul0A}i@NlOBj4e;q*6{SUAfLwq_8P;R@9&u?HZ8E)uT>+wO+tb< zpz%X-k?Ykx3JUH|L4n9X2w>Q^djjPZ+~K_|E(wgU^v;`B4N_b#;OuFtr2HP~*-un= z7AP)IBbO6W91bY1t1^{xcNtCaIL`PSN1h2|4PbTcmtKo?>=h4=2;OfPJ9{UP(a*-V zGg*bK{L7@bvemKeUjGiKBqE{^-@}l8oA4qD6vuGvrr&GEM6a?~m{CtFK&V6uBZKHQ zsM6JlVsUH7gETMbAq!H~6^%dA60%X42Qac1a?Dfrw<*XG0k%>|I?lC=Z5=#J4FjOr zH>*d9emuDa{ZNX7Vg3E7f5HnI2MQUMOPu4 zE*`X9u7_%i(#u}OcKR=Zoog>|u(F)u|S`?8S| z0c?5coxqa$k^1|@M@>MC5B`X@XE1m-nKOq&M#;6$@R6JjlWN)ckP#_pVQAZ(rtvN) zv$#L4Ny4bY!=z2dcxkd^b|l83POD-r{BD+k>v&$v`ug{pdh6WH3YHRMp;%uNrM{Euj4rfBdJ5j$NitJYrSNO!M|wZsns#XU1B zBCD$UVhgd|W}`3j>>BG@gTK)TTD17jw=z-%E5}iR;&H=LYm{)gZUR4M)sK!_GXoLw zDk~sYw0GlcmVDP*sUGs`L>Hs^`kezIQsBDhmNC(@n23@wr|xQ}>eb7MV6q*Rys(a2 zj;J-$3JjFloQ0pCYW#SJQ7GWLmI19nscUMxRtK)nZR;|><#!K_eii#;;*OQw9;3`A z4Lx)qfONDG!0A2MWxV?>$eD$#xb74%b0(LZBLoc+NHKwyC<d^=gv%s_ zo_*n!vXvpFT+6nYamz-lpkkGibVloFR9fI>!*G3j7+DySovqskm1VWn(W z+2>)yZelJSRds7bI;vQ`erb06O?=(hM3%k{+nw(3luno#uGiUI`y1Gwy>+ZkpB)`F zlE;J!2bTDnW)$~(j{9&@L}l>(!YuHMORiq=%U5kpVQ1rgt#!*PO%>L96X3YS<=Ofq zRAW31_a-yf!Y{%S_H({>{6|7LSd-pZo3oT{^-GwfXQIvQ^Wm+^HEB!BLxB<4F_Se@ zmM6RtQxuFv_B5?h5>f_g$+W77W~vfG_+nE74$9-c2sz~LtH3ic@4azIn*R)4aP-mP zL#M-v`N~b*ncS;d^A3Dn;^Lw+6fo8Iev{iQlZ$nmPOy!fEnnWGe-rPd z=}9&GVyXxs)9b9av{2Uz8@75Ack)f#9pk0)$uH?8E2zp%8UxoJL2?lmH``V*uZDY* zVcE@FHcZ|P*T->-ujG)^r7lX@g7Ai6PEsX9-_Gd0I$^yxh%rNDitVTZ&m z%DyY3<2F3LSIZe!RXMk>Z{kz~q`4M!OIogu<1pN6ZM`O~e6cMIj>x78Y&%#4K`$*& zm(J8xtTRVXpCXO!7qY+Wjb*&hz6^@4EC)zlGODw9oi3+CDARA8B7i@(V7vfpMQ9)a z-op#9Ruqb#JAC0aQFw0^mhv$xRSmCXF&buq3<~DXekWoVFKFW_Qs&-hriD}yRY3q* zoU=datRlh_N&lq~WvKSRuMx*wJV1r9!|+cv9XurA*3ZkiX|KP;Uf=9xvu2oc>-MDI z7s~N7qEA_wCER*)o3Mgg0umzD9pX|`0v#cY2=9^9#GX@dYD2HrOu2EVMud5EKD^=c)J*kb&iZ@#zTwha-yba3j>Hsy ztccO~UTDkf_G$IWf1|@`Ge<}^_h1#kd(Cs$u|N?QpYR-=aB$t#G>;LL+^#B}-Y~d3 z*txJJF_F?fSJ~f4_B*3$C(qbm252hF z#qHnDj;u5WFC)_B4B~wFmW@}gL?COQxFroL!yEMJQUA0WJUE03KzO`-lrergK3`)3 zNU6I{l1|7j|A3A4sb`Fc*v*YFJkm8P`U){>LpTnlp*$r&W|GND2XAoCOq&ztWxIuF zcY;oV?JBq*-=Qs0v|~wKb^3%woRgyGOH#694BdR5tbWbs2lUjj!l^*cY({E}{7(~!?_Lp6N!Gx2Gy;z|=Q+-dR~oVP!*Q@=}VwX2M$1_wVV z5c)JhB7_vqa1*2-zj}~E8OB)#kgz14d-!nIJX)Bh0sLe})Z!%&tiOfP3W8bbirIiz zu3EPH`cz$Rz2W-jyU}7ph|4D3pPbuAQNk2aWOMaitO!PjG7efE@4_aAP{)z*N@hxh z75@2D8@4%cEl5E1<(2?BPMH_<=hw@7%-ob{ay*7EsHRAmGpN)BR z4)*Xn^G*AG89XUArVsQ?O;FFnS3m;I*USl71hqb3^9x7L_C#xkLx3d|5tV>n43GC_ z2YHTx9Rly~nZ>7`6$Mu;HGxa@rb93AOF!j?BfZ&CNWJ`RBmnxeNjPXElndAjcHY%$U-BA6P{e8ov+ zC+YWKhIk8qZ%YMPcs1U_4T+BK4r*=y>awM1ZsTkzw``GGo9uFy^=UUt^k!{5i}C?@ zqsol*8)SZ~G%H=KpDUA#X|VN7X4dc02SQ4m!S5aD<)YM%$;X7M^MrNqgsB;TWFvT* znXg<((Dz+yFgA^wPocgE=RAwx9(tkYknX}Zx5kehN((_<8EpZ#_@6+I9*ZiM{#vj( zTYEz7sI2)FeL`q^#s{G2tq}7VvQ=&H{C+Lw<=?aWzg|sw0JCQkARSYAyNI;xOu6ow zw6!rRw%OnShYfQs?{~COrFU907-o5+(H9u?V!}L zAQjO*_9?>%nCTs=;iS?{ig@289eu%X{+7KfTc~KVI8rN?yI*{r8WFe0y`x-Q2MTQh znFY_=eZb}0_SDb5VlI87;-(f&!7OeYW;o+lHJE#AFg;zeaTZ*U`~-Jwj52_(QXO1v zZ0s?2&LY`4u;fdnIo zcVg;CxgoUwC6a9fSf2&@RyOSM+loi7jvfo5y`Wpm7_dp{*6ZYkpF)YFzx;~Bt{BQ$ z$oWoW7GuAk33|F5!SiIQXo9+iPg1mEx%`4joxk6k-z$Cvh6=p>3u&3vK^a+0QA{#w zf(qe1HYkUUIMAY6Kkl{G=+w+FcQs(-V~4Qh+8EYpFejj+Vpz6**tC9F9R(W(SZ&V6m0A3I?@-K*73 zF^(9}KMAtbCyOW}8S~aCMy~i?zCJa9NZ2r4@+K7lyg!oxpxMxgc>>8w9z0+A76Zv{ zM>dfX20)YtazT@Coulnep=^d!cbmOEnOq$=JXbuTFq3Xn?vo(?$*U?WOE;biZRB!} z*FV1P0fz-}85b@_df00W#QU!4FkvR>_`%KoVX>SEF=Z&W*Gt>mU_`T_2jx#|=NFfgb9gYGrkZ}B@ zlisCBiEv}WPZ6x)O5$Ugyl_;&F#v-jT1l?h5kBx+l>rfqv)xsdbE2fX@}e2Ch8HugRQpFD@X+!>z-T~}!XbBwU+~G%em-ZiI!tof?Cx?lCKh~_U$fqyp>5FIV?LuiMa`}Mg*Q|DF!+T z4ZEwf@Qrh(0XGx&mOmB-&f#m8m%=kbww3(fRjCP921;}pARNK-@O82DJLp~OV!L&H zUJWR2&f32IPi|mlfH_U`zNzTFl4N!U$XDcb0p+#}sA2#f0@d&;Y_A<1^fv$`b#t5g zKmuO_>jD|9a7PmXpCn&f0?e5i88bp|?QbhCI~4TK*MBg2 ztsV5kVIUm<#kfvwz#8%<3)C;f@=pnb8&d;UgiO;uu|0aiCNPzWflkEUg(L^iBWWDt zzfJZv7D2>>CQZBo zG*oxV5O>!A>??qwrs2n_$Ul2ZQ3fP6Wt18~xx!B+4awIQIJpnW&qbhxCv6b=h8aA- ziI#umWG5D2xnM1U*6U$LFvOe;U~Um>Nxf%(dG;9qH2jMSwBFp151!+yRpkCP)Dn`` zB7P0LGVbb`ZDy$P^RHY@B)ExtkNhQE1>6W5&rv{v8wRRWs`yQ0k7C*fZvtsb#^f4C z>d&68{Q^1;SGSSi*keyH9T06_nCaO4K)4F9I)*2Q_AYM@JfPEF6hcb>#tX#eCgA`* z|7U5zD1oD;{gsjj+S>4p1avLQ76UD;{&yZ3Q~@`Gwojp{@mWsLlX2Rk!o6zl9xM~6 z%0^{`81mr?KyY2oJpxM4E0VOcAkx-pG~{ohLK#m5aYXpdbR)G*QwJ zwRb_*GAj$9+JBme%l1+!vgZXs`h3Y!24^>{)+7= zuL$Nj83q0rXrA+*4XQ~QXruXvwFDGVKLbT)9l9z=$m;&pS3iFQNV4i|JP)msO`HeW zXx9CHD0uu=Y3+mG$LG?|2ZkY<%79ZG0R@479iLG5pD2J0lK*b43?XC|ALWfyG7vlc z+)qBS#!qIC@&rSsqlgcMzXe!~@0loyQxxM`kiDdk!MBL}dFWW)GWd}11AhuvRAsX+ H-Marj%SvG; literal 0 HcmV?d00001 diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index 33ad1660c2abf7..fd86906f4b9890 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -15,7 +15,7 @@ if your data is stored in {es} and contains a time field, you can use the *{data-viz}* to identify possible fields for {anomaly-detect}: [role="screenshot"] -image::user/ml/images/ml-data-visualizer-sample.jpg[{data-viz} for sample flight data] +image::user/ml/images/ml-data-visualizer-sample.png[{data-viz} for sample flight data] You can also upload a CSV, NDJSON, or log file. The *{data-viz}* identifies the file format and field mappings. You can then optionally import From 837343a6f5b939fcede11c045d03d6aca805f0bd Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Thu, 11 Aug 2022 17:23:28 +0200 Subject: [PATCH 21/59] Skip Prometheus monitoring collection test when running on cloud (#138003) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../test/api_integration/apis/monitoring_collection/index.ts | 2 +- .../api_integration/apis/monitoring_collection/prometheus.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/test/api_integration/apis/monitoring_collection/index.ts b/x-pack/test/api_integration/apis/monitoring_collection/index.ts index e89bd44963c031..092cd93a480a72 100644 --- a/x-pack/test/api_integration/apis/monitoring_collection/index.ts +++ b/x-pack/test/api_integration/apis/monitoring_collection/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { - describe('Monitoring Collection', function taskManagerSuite() { + describe('Monitoring Collection', () => { loadTestFile(require.resolve('./prometheus')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring_collection/prometheus.ts b/x-pack/test/api_integration/apis/monitoring_collection/prometheus.ts index 0ac13dda92cb5d..7820ab80b5847c 100644 --- a/x-pack/test/api_integration/apis/monitoring_collection/prometheus.ts +++ b/x-pack/test/api_integration/apis/monitoring_collection/prometheus.ts @@ -11,7 +11,9 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - describe('Prometheus endpoint', () => { + describe('Prometheus endpoint', function () { + this.tags(['skipCloud']); + it('returns prometheus scraped metrics', async () => { await supertest.post('/api/generate_otel_metrics').set('kbn-xsrf', 'foo').expect(200); const response = await supertest.get('/api/monitoring_collection/v1/prometheus').expect(200); From d30f367eb3498e1a3d3112296342023ddd3c7272 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Thu, 11 Aug 2022 18:33:11 +0300 Subject: [PATCH 22/59] [XY] Migrate vis type xy to new unified xy expression (#136475) * Migrate vis type xy to new unified xy expression * Add legend toggle and color picker. Some fixes * Fix snapshots * Fix tests * Fix some tests * Fix snapshots * Fix tests * Fix some tests * Fix some tests * Fix some more tests * Update snapshot for area chart * Fix dashboards tests * Fix test * Fix some remarks * Fix tests * Fix test * Remove useAdjustedInterval arg * Fix remarks * Fix CI checks * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * Fix CI * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * Fix all remarks * Remove unused code * Fix Percentile aggragtion * Fix problems with several series * Fix problems with hidden series Co-authored-by: Joe Reuter Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Stratoula Kalafateli --- .../expression_xy/common/constants.ts | 4 + .../axis_extent_config.ts | 6 + .../common_data_layer_args.ts | 8 +- .../expression_functions/common_xy_args.ts | 7 - .../extended_data_layer.ts | 12 +- .../extended_data_layer_fn.ts | 8 +- .../expression_functions/layered_xy_vis.ts | 18 +- .../expression_functions/layered_xy_vis_fn.ts | 10 +- .../common/expression_functions/validate.ts | 2 +- .../common/expression_functions/xy_vis_fn.ts | 26 +- .../expression_xy/common/helpers/table.ts | 5 +- .../expression_xy/common/i18n/index.tsx | 12 + .../common/types/expression_functions.ts | 25 +- .../expression_xy/common/utils/index.tsx | 2 +- .../common/utils/log_datatables.ts | 59 +- .../__snapshots__/xy_chart.test.tsx.snap | 16836 +++++++++------- .../public/components/data_layers.tsx | 71 +- .../public/components/legend_action.tsx | 6 +- .../public/components/legend_color_picker.tsx | 142 + .../components/reference_lines/utils.tsx | 7 + .../public/components/split_chart.tsx | 32 +- .../components/tooltip/tooltip.test.tsx | 16 +- .../public/components/tooltip/tooltip.tsx | 33 +- .../public/components/x_domain.tsx | 29 +- .../public/components/xy_chart.test.tsx | 12 +- .../public/components/xy_chart.tsx | 645 +- .../public/definitions/visualizations.ts | 1 + .../xy_chart_renderer.tsx | 14 +- .../public/helpers/color_assignment.test.ts | 145 +- .../public/helpers/color_assignment.ts | 28 +- .../public/helpers/data_layers.tsx | 119 +- .../expression_xy/public/helpers/layers.ts | 21 +- .../public/__snapshots__/to_ast.test.ts.snap | 62 +- src/plugins/vis_types/xy/public/to_ast.ts | 429 +- .../dashboard/group1/embeddable_rendering.ts | 12 +- .../apps/dashboard/group3/dashboard_state.ts | 2 +- .../apps/getting_started/_shakespeare.ts | 2 +- .../apps/visualize/group2/_inspector.ts | 4 +- .../_area_chart.ts | 2 +- .../_line_chart_split_chart.ts | 12 +- .../_line_chart_split_series.ts | 12 +- .../_point_series_options.ts | 2 +- .../_vertical_bar_chart.ts | 2 +- .../_vertical_bar_chart_nontimeindex.ts | 2 +- .../page_objects/visualize_chart_page.ts | 4 +- .../screenshots/baseline/area_chart.png | Bin 190127 -> 190569 bytes .../__snapshots__/to_expression.test.ts.snap | 12 +- .../public/visualizations/xy/to_expression.ts | 52 +- .../dashboard_async/async_search.json | 2 +- .../dashboard/async_search/async_search.ts | 2 +- .../async_search/save_search_session.ts | 2 +- 51 files changed, 10969 insertions(+), 8009 deletions(-) create mode 100644 src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx diff --git a/src/plugins/chart_expressions/expression_xy/common/constants.ts b/src/plugins/chart_expressions/expression_xy/common/constants.ts index 5d9d7fb70d478f..8116f0146f19a1 100644 --- a/src/plugins/chart_expressions/expression_xy/common/constants.ts +++ b/src/plugins/chart_expressions/expression_xy/common/constants.ts @@ -35,6 +35,8 @@ export const FittingFunctions = { LINEAR: 'Linear', CARRY: 'Carry', LOOKAHEAD: 'Lookahead', + AVERAGE: 'Average', + NEAREST: 'Nearest', } as const; export const EndValues = { @@ -60,6 +62,7 @@ export const LineStyles = { SOLID: 'solid', DASHED: 'dashed', DOTTED: 'dotted', + DOT_DASHED: 'dot-dashed', } as const; export const FillStyles = { @@ -98,6 +101,7 @@ export const XScaleTypes = { export const XYCurveTypes = { LINEAR: 'LINEAR', CURVE_MONOTONE_X: 'CURVE_MONOTONE_X', + CURVE_STEP_AFTER: 'CURVE_STEP_AFTER', } as const; export const ValueLabelModes = { diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/axis_extent_config.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/axis_extent_config.ts index c1a4070225a645..613b631d8c9c4b 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/axis_extent_config.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/axis_extent_config.ts @@ -53,6 +53,12 @@ export const axisExtentConfigFunction: ExpressionFunctionDefinition< defaultMessage: 'Upper bound', }), }, + enforce: { + types: ['boolean'], + help: i18n.translate('expressionXY.axisExtentConfig.enforce.help', { + defaultMessage: 'Enforce extent params.', + }), + }, }, fn(input, args) { if (args.mode === AxisExtentModes.CUSTOM) { diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_data_layer_args.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_data_layer_args.ts index 0c173ea0754f8b..10f6d5d748b23d 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_data_layer_args.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_data_layer_args.ts @@ -7,7 +7,7 @@ */ import { ArgumentType } from '@kbn/expressions-plugin/common'; -import { SeriesTypes, XScaleTypes, DATA_DECORATION_CONFIG } from '../constants'; +import { SeriesTypes, XScaleTypes, DATA_DECORATION_CONFIG, XYCurveTypes } from '../constants'; import { strings } from '../i18n'; import { DataLayerArgs, ExtendedDataLayerArgs } from '../types'; @@ -58,6 +58,12 @@ export const commonDataLayerArgs: Omit< default: false, help: strings.getIsHorizontalHelp(), }, + curveType: { + types: ['string'], + options: [...Object.values(XYCurveTypes)], + help: strings.getCurveTypeHelp(), + strict: true, + }, lineWidth: { types: ['number'], help: strings.getLineWidthHelp(), diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_xy_args.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_xy_args.ts index df9c4abdfe22e4..799dc12b1ea5bb 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_xy_args.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/common_xy_args.ts @@ -11,7 +11,6 @@ import { FittingFunctions, LEGEND_CONFIG, ValueLabelModes, - XYCurveTypes, X_AXIS_CONFIG, Y_AXIS_CONFIG, } from '../constants'; @@ -50,12 +49,6 @@ export const commonXYArgs: CommonXYFn['args'] = { strict: true, default: ValueLabelModes.HIDE, }, - curveType: { - types: ['string'], - options: [...Object.values(XYCurveTypes)], - help: strings.getCurveTypeHelp(), - strict: true, - }, fillOpacity: { types: ['number'], help: strings.getFillOpacityHelp(), diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer.ts index 17c6485c711dae..d0d65cc72732d6 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer.ts @@ -20,27 +20,23 @@ export const extendedDataLayerFunction: ExtendedDataLayerFn = { args: { ...commonDataLayerArgs, xAccessor: { - types: ['string'], + types: ['vis_dimension', 'string'], help: strings.getXAccessorHelp(), }, splitAccessors: { - types: ['string'], + types: ['vis_dimension', 'string'], help: strings.getSplitAccessorHelp(), multi: true, }, accessors: { - types: ['string'], + types: ['vis_dimension', 'string'], help: strings.getAccessorsHelp(), multi: true, }, markSizeAccessor: { - types: ['string'], + types: ['vis_dimension', 'string'], help: strings.getMarkSizeAccessorHelp(), }, - table: { - types: ['datatable'], - help: strings.getTableHelp(), - }, layerId: { types: ['string'], help: strings.getLayerIdHelp(), diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer_fn.ts index 16905f96f9c2ff..79612971e841b8 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/extended_data_layer_fn.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { validateAccessor } from '@kbn/visualizations-plugin/common/utils'; import { ExtendedDataLayerArgs, ExtendedDataLayerFn } from '../types'; import { EXTENDED_DATA_LAYER, LayerTypes } from '../constants'; @@ -19,8 +20,11 @@ import { } from './validate'; export const extendedDataLayerFn: ExtendedDataLayerFn['fn'] = async (data, args, context) => { - const table = args.table ?? data; - const accessors = getAccessors(args, table); + const table = data; + const accessors = getAccessors( + args, + table + ); validateAccessor(accessors.xAccessor, table.columns); accessors.splitAccessors?.forEach((accessor) => validateAccessor(accessor, table.columns)); diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.ts index f419891e079ea7..392c9a0d5830ac 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis.ts @@ -13,6 +13,7 @@ import { REFERENCE_LINE_LAYER, LAYERED_XY_VIS, EXTENDED_ANNOTATION_LAYER, + REFERENCE_LINE, } from '../constants'; import { commonXYArgs } from './common_xy_args'; import { strings } from '../i18n'; @@ -25,12 +26,27 @@ export const layeredXyVisFunction: LayeredXyVisFn = { args: { ...commonXYArgs, layers: { - types: [EXTENDED_DATA_LAYER, REFERENCE_LINE_LAYER, EXTENDED_ANNOTATION_LAYER], + types: [EXTENDED_DATA_LAYER, REFERENCE_LINE_LAYER, EXTENDED_ANNOTATION_LAYER, REFERENCE_LINE], help: i18n.translate('expressionXY.layeredXyVis.layers.help', { defaultMessage: 'Layers of visual series', }), multi: true, }, + splitColumnAccessor: { + types: ['vis_dimension', 'string'], + help: strings.getSplitColumnAccessorHelp(), + }, + splitRowAccessor: { + types: ['vis_dimension', 'string'], + help: strings.getSplitRowAccessorHelp(), + }, + singleTable: { + types: ['boolean'], + help: i18n.translate('expressionXY.layeredXyVis.singleTable.help', { + defaultMessage: 'All layers use the one datatable', + }), + default: false, + }, }, async fn(data, args, handlers) { const { layeredXyVisFn } = await import('./layered_xy_vis_fn'); diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts index 9e1ef1cc0cb9f3..50549d5f8ac1ca 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/layered_xy_vis_fn.ts @@ -8,7 +8,7 @@ import { XY_VIS_RENDERER } from '../constants'; import { LayeredXyVisFn } from '../types'; -import { logDatatables } from '../utils'; +import { logDatatables, logDatatable } from '../utils'; import { validateMarkSizeRatioLimits, validateAddTimeMarker, @@ -21,10 +21,14 @@ import { appendLayerIds, getDataLayers } from '../helpers'; export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers) => { const layers = appendLayerIds(args.layers ?? [], 'layers'); + const dataLayers = getDataLayers(layers); - logDatatables(layers, handlers); + if (args.singleTable) { + logDatatable(data, layers, handlers, args.splitColumnAccessor, args.splitRowAccessor); + } else { + logDatatables(layers, handlers, args.splitColumnAccessor, args.splitRowAccessor); + } - const dataLayers = getDataLayers(layers); const hasBar = hasBarLayer(dataLayers); validateAddTimeMarker(dataLayers, args.addTimeMarker); validateMarkSizeRatioLimits(args.markSizeRatio); diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts index 9b8183abfa2056..6c88d0ff6a62cb 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/validate.ts @@ -171,7 +171,7 @@ export const validateExtents = ( xAxisConfig?: XAxisConfigResult ) => { yAxisConfigs?.forEach((axis) => { - if (!axis.extent) { + if (!axis.extent || axis.extent.enforce) { return; } if ( diff --git a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts index 789b7fb9ceb639..2808b861c6df85 100644 --- a/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts +++ b/src/plugins/chart_expressions/expression_xy/common/expression_functions/xy_vis_fn.ts @@ -6,17 +6,12 @@ * Side Public License, v 1. */ -import { - Dimension, - prepareLogTable, - validateAccessor, -} from '@kbn/visualizations-plugin/common/utils'; +import { validateAccessor } from '@kbn/visualizations-plugin/common/utils'; import type { Datatable } from '@kbn/expressions-plugin/common'; import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common/expression_functions'; -import { LayerTypes, XY_VIS_RENDERER, DATA_LAYER, REFERENCE_LINE } from '../constants'; +import { LayerTypes, XY_VIS_RENDERER, DATA_LAYER } from '../constants'; import { appendLayerIds, getAccessors, getShowLines, normalizeTable } from '../helpers'; import { DataLayerConfigResult, XYLayerConfig, XyVisFn, XYArgs } from '../types'; -import { getLayerDimensions } from '../utils'; import { hasAreaLayer, hasBarLayer, @@ -35,6 +30,7 @@ import { validateLinesVisibilityForChartType, validateAxes, } from './validate'; +import { logDatatable } from '../utils'; const createDataLayer = (args: XYArgs, table: Datatable): DataLayerConfigResult => { const accessors = getAccessors(args, table); @@ -108,21 +104,7 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => { ...appendLayerIds(annotationLayers, 'annotationLayers'), ]; - if (handlers.inspectorAdapters.tables) { - handlers.inspectorAdapters.tables.reset(); - handlers.inspectorAdapters.tables.allowCsvExport = true; - - const layerDimensions = layers.reduce((dimensions, layer) => { - if (layer.layerType === LayerTypes.ANNOTATIONS || layer.type === REFERENCE_LINE) { - return dimensions; - } - - return [...dimensions, ...getLayerDimensions(layer)]; - }, []); - - const logTable = prepareLogTable(data, layerDimensions, true); - handlers.inspectorAdapters.tables.logDatatable('default', logTable); - } + logDatatable(data, layers, handlers, args.splitColumnAccessor, args.splitRowAccessor); const hasBar = hasBarLayer(dataLayers); const hasArea = hasAreaLayer(dataLayers); diff --git a/src/plugins/chart_expressions/expression_xy/common/helpers/table.ts b/src/plugins/chart_expressions/expression_xy/common/helpers/table.ts index 65cae152c0caf5..09171f8f72ff58 100644 --- a/src/plugins/chart_expressions/expression_xy/common/helpers/table.ts +++ b/src/plugins/chart_expressions/expression_xy/common/helpers/table.ts @@ -15,7 +15,10 @@ export function normalizeTable(data: Datatable, xAccessor?: string | ExpressionV const xColumn = xAccessor && getColumnByAccessor(xAccessor, data.columns); if (xColumn && xColumn?.meta.type === 'date') { const xColumnId = xColumn.id; - if (!data.rows.some((row) => typeof row[xColumnId] === 'string')) return data; + if ( + !data.rows.some((row) => typeof row[xColumnId] === 'string' && row[xColumnId] !== '__other__') + ) + return data; const rows = data.rows.map((row) => { return typeof row[xColumnId] !== 'string' ? row diff --git a/src/plugins/chart_expressions/expression_xy/common/i18n/index.tsx b/src/plugins/chart_expressions/expression_xy/common/i18n/index.tsx index 75a523ab41d92f..1e9df3c3ffe64c 100644 --- a/src/plugins/chart_expressions/expression_xy/common/i18n/index.tsx +++ b/src/plugins/chart_expressions/expression_xy/common/i18n/index.tsx @@ -25,6 +25,18 @@ export const strings = { i18n.translate('expressionXY.xyVis.logDatatable.breakDown', { defaultMessage: 'Break down by', }), + getSplitRowHelp: () => + i18n.translate('expressionXY.xyVis.logDatatable.splitRow', { + defaultMessage: 'Split rows by', + }), + getSplitColumnHelp: () => + i18n.translate('expressionXY.xyVis.logDatatable.splitColumn', { + defaultMessage: 'Split columns by', + }), + getMarkSizeHelp: () => + i18n.translate('expressionXY.xyVis.logDatatable.markSize', { + defaultMessage: 'Mark size', + }), getReferenceLineHelp: () => i18n.translate('expressionXY.xyVis.logDatatable.breakDown', { defaultMessage: 'Break down by', diff --git a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts index 12727973ea4eda..0970cec985d308 100644 --- a/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts @@ -71,6 +71,7 @@ export interface AxisExtentConfig { mode: AxisExtentMode; lowerBound?: number; upperBound?: number; + enforce?: boolean; } export interface AxisConfig { @@ -130,6 +131,7 @@ export interface DataLayerArgs { isHorizontal: boolean; palette: PaletteOutput; decorations?: DataDecorationConfigResult[]; + curveType?: XYCurveType; } export interface ValidLayer extends DataLayerConfigResult { @@ -138,12 +140,12 @@ export interface ValidLayer extends DataLayerConfigResult { export interface ExtendedDataLayerArgs { layerId?: string; - accessors: string[]; + accessors: Array; seriesType: SeriesType; - xAccessor?: string; + xAccessor?: string | ExpressionValueVisDimension; simpleView?: boolean; - splitAccessors?: string[]; - markSizeAccessor?: string; + splitAccessors?: Array; + markSizeAccessor?: string | ExpressionValueVisDimension; lineWidth?: number; showPoints?: boolean; showLines?: boolean; @@ -157,7 +159,7 @@ export interface ExtendedDataLayerArgs { palette: PaletteOutput; // palette will always be set on the expression decorations?: DataDecorationConfigResult[]; - table?: Datatable; + curveType?: XYCurveType; } export interface LegendConfig { @@ -215,7 +217,6 @@ export interface XYArgs extends DataLayerArgs { referenceLines: ReferenceLineConfigResult[]; annotationLayers: AnnotationLayerConfigResult[]; fittingFunction?: FittingFunction; - curveType?: XYCurveType; fillOpacity?: number; hideEndzones?: boolean; valuesInLegend?: boolean; @@ -239,7 +240,6 @@ export interface LayeredXYArgs { valueLabels: ValueLabelMode; layers?: XYExtendedLayerConfigResult[]; fittingFunction?: FittingFunction; - curveType?: XYCurveType; fillOpacity?: number; hideEndzones?: boolean; valuesInLegend?: boolean; @@ -252,6 +252,9 @@ export interface LayeredXYArgs { minTimeBarInterval?: string; orderBucketsBySum?: boolean; showTooltip: boolean; + splitRowAccessor?: ExpressionValueVisDimension | string; + splitColumnAccessor?: ExpressionValueVisDimension | string; + singleTable?: boolean; } export interface XYProps { @@ -261,7 +264,6 @@ export interface XYProps { valueLabels: ValueLabelMode; layers: CommonXYLayerConfig[]; fittingFunction?: FittingFunction; - curveType?: XYCurveType; fillOpacity?: number; hideEndzones?: boolean; valuesInLegend?: boolean; @@ -276,6 +278,7 @@ export interface XYProps { detailedTooltip?: boolean; orderBucketsBySum?: boolean; showTooltip: boolean; + singleTable?: boolean; } export interface AnnotationLayerArgs { @@ -317,12 +320,14 @@ export type XYLayerConfig = DataLayerConfig | ReferenceLineConfig | AnnotationLa export type XYExtendedLayerConfig = | ExtendedDataLayerConfig | ReferenceLineLayerConfig - | ExtendedAnnotationLayerConfig; + | ExtendedAnnotationLayerConfig + | ReferenceLineConfig; export type XYExtendedLayerConfigResult = | ExtendedDataLayerConfigResult | ReferenceLineLayerConfigResult - | ExtendedAnnotationLayerConfigResult; + | ExtendedAnnotationLayerConfigResult + | ReferenceLineConfigResult; export interface ExtendedReferenceLineDecorationConfig extends ReferenceLineArgs { type: typeof EXTENDED_REFERENCE_LINE_DECORATION_CONFIG; diff --git a/src/plugins/chart_expressions/expression_xy/common/utils/index.tsx b/src/plugins/chart_expressions/expression_xy/common/utils/index.tsx index ba40d5768f50c0..b367b14b0e1171 100644 --- a/src/plugins/chart_expressions/expression_xy/common/utils/index.tsx +++ b/src/plugins/chart_expressions/expression_xy/common/utils/index.tsx @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { logDatatables, getLayerDimensions } from './log_datatables'; +export { logDatatables, logDatatable, getLayerDimensions } from './log_datatables'; diff --git a/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts b/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts index d9bbd56f6f3232..5b04b1bdf0d426 100644 --- a/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts +++ b/src/plugins/chart_expressions/expression_xy/common/utils/log_datatables.ts @@ -6,13 +6,19 @@ * Side Public License, v 1. */ -import { ExecutionContext } from '@kbn/expressions-plugin/common'; +import { Datatable, ExecutionContext } from '@kbn/expressions-plugin/common'; +import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { Dimension, prepareLogTable } from '@kbn/visualizations-plugin/common/utils'; import { LayerTypes, REFERENCE_LINE } from '../constants'; import { strings } from '../i18n'; import { CommonXYDataLayerConfig, CommonXYLayerConfig, ReferenceLineLayerConfig } from '../types'; -export const logDatatables = (layers: CommonXYLayerConfig[], handlers: ExecutionContext) => { +export const logDatatables = ( + layers: CommonXYLayerConfig[], + handlers: ExecutionContext, + splitColumnAccessor?: string | ExpressionValueVisDimension, + splitRowAccessor?: string | ExpressionValueVisDimension +) => { if (!handlers?.inspectorAdapters?.tables) { return; } @@ -25,19 +31,65 @@ export const logDatatables = (layers: CommonXYLayerConfig[], handlers: Execution return; } - const logTable = prepareLogTable(layer.table, getLayerDimensions(layer), true); + const layerDimensions = getLayerDimensions(layer); + + layerDimensions.push([ + splitColumnAccessor ? [splitColumnAccessor] : undefined, + strings.getSplitColumnHelp(), + ]); + layerDimensions.push([ + splitRowAccessor ? [splitRowAccessor] : undefined, + strings.getSplitRowHelp(), + ]); + + const logTable = prepareLogTable(layer.table, layerDimensions, true); handlers.inspectorAdapters.tables.logDatatable(layer.layerId, logTable); }); }; +export const logDatatable = ( + data: Datatable, + layers: CommonXYLayerConfig[], + handlers: ExecutionContext, + splitColumnAccessor?: string | ExpressionValueVisDimension, + splitRowAccessor?: string | ExpressionValueVisDimension +) => { + if (handlers.inspectorAdapters.tables) { + handlers.inspectorAdapters.tables.reset(); + handlers.inspectorAdapters.tables.allowCsvExport = true; + + const layerDimensions = layers.reduce((dimensions, layer) => { + if (layer.layerType === LayerTypes.ANNOTATIONS || layer.type === REFERENCE_LINE) { + return dimensions; + } + + return [...dimensions, ...getLayerDimensions(layer)]; + }, []); + + layerDimensions.push([ + splitColumnAccessor ? [splitColumnAccessor] : undefined, + strings.getSplitColumnHelp(), + ]); + layerDimensions.push([ + splitRowAccessor ? [splitRowAccessor] : undefined, + strings.getSplitRowHelp(), + ]); + + const logTable = prepareLogTable(data, layerDimensions, true); + handlers.inspectorAdapters.tables.logDatatable('default', logTable); + } +}; + export const getLayerDimensions = ( layer: CommonXYDataLayerConfig | ReferenceLineLayerConfig ): Dimension[] => { let xAccessor; let splitAccessors; + let markSizeAccessor; if (layer.layerType === LayerTypes.DATA) { xAccessor = layer.xAccessor; splitAccessors = layer.splitAccessors; + markSizeAccessor = layer.markSizeAccessor; } const { accessors, layerType } = layer; @@ -48,5 +100,6 @@ export const getLayerDimensions = ( ], [xAccessor ? [xAccessor] : undefined, strings.getXAxisHelp()], [splitAccessors ? splitAccessors : undefined, strings.getBreakdownHelp()], + [markSizeAccessor ? [markSizeAccessor] : undefined, strings.getMarkSizeHelp()], ]; }; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index 24c7d68cd6fdad..e92644d7d2fb5e 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -281,3014 +281,937 @@ Array [ `; exports[`XYChart component it renders area 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - - -`; - -exports[`XYChart component it renders bar 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - - -`; - -exports[`XYChart component it renders horizontal bar 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={90} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - - -`; - -exports[`XYChart component it renders line 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ Object { - "type": "return", - "value": Object { - "convert": [MockFunction] { - "calls": Array [ - Array [ - 1652034840000, - ], - Array [ - 1652122440000, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": 1652034840000, - }, - Object { - "type": "return", - "value": 1652122440000, - }, - ], - }, + "background": Object { + "color": undefined, }, - }, - Object { - "type": "return", - "value": Object { - "convert": [MockFunction] { - "calls": Array [ - Array [ - 1652034840000, - ], - Array [ - 1652122440000, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": 1652034840000, - }, - Object { - "type": "return", - "value": 1652122440000, - }, - ], + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - }, + "markSizeRatio": undefined, + } + } + tooltip={ Object { - "type": "return", - "value": Object { - "convert": [MockFunction] { - "calls": Array [ - Array [ - 1652034840000, - ], - Array [ - 1652122440000, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": 1652034840000, - }, - Object { - "type": "return", - "value": 1652122440000, - }, - ], - }, + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + - -`; - -exports[`XYChart component it renders stacked area 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - + + + +`; + +exports[`XYChart component it renders bar 1`] = ` +

    + + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - }, + "markSizeRatio": undefined, + } + } + tooltip={ Object { - "type": "return", - "value": Object { - "convert": [MockFunction] { - "calls": Array [ - Array [ - 1652034840000, - ], - Array [ - 1652122440000, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": 1652034840000, - }, - Object { - "type": "return", - "value": 1652122440000, - }, - ], - }, + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + - -`; - -exports[`XYChart component it renders stacked bar 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - + + +
    +`; + +exports[`XYChart component it renders horizontal bar 1`] = ` +
    + + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={90} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + + +
    +`; + +exports[`XYChart component it renders line 1`] = ` +
    + - -`; - -exports[`XYChart component it renders stacked horizontal bar 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={90} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - - - + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + + +
    +`; + +exports[`XYChart component it renders stacked area 1`] = ` +
    + - -`; - -exports[`XYChart component split chart should render split chart if both, splitRowAccessor and splitColumnAccessor are specified 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + - - - + + +
    +`; + +exports[`XYChart component it renders stacked bar 1`] = ` +
    + + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + + +
    +`; + +exports[`XYChart component it renders stacked horizontal bar 1`] = ` +
    + - -`; - -exports[`XYChart component split chart should render split chart if splitColumnAccessor is specified 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={90} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + - - - + + +
    +`; + +exports[`XYChart component split chart should render split chart if both, splitRowAccessor and splitColumnAccessor are specified 1`] = ` +
    + + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + + + +
    +`; + +exports[`XYChart component split chart should render split chart if splitColumnAccessor is specified 1`] = ` +
    + - -`; - -exports[`XYChart component split chart should render split chart if splitRowAccessor is specified 1`] = ` - - - } - onBrushEnd={[Function]} - onElementClick={[Function]} - onPointerUpdate={[Function]} - onRenderChange={[Function]} - rotation={0} - showLegend={false} - showLegendExtra={false} - theme={ - Object { - "background": Object { - "color": undefined, - }, - "barSeriesStyle": Object {}, - "chartMargins": Object {}, - "legend": Object { - "labelOptions": Object { - "maxLines": 0, - }, - }, - "markSizeRatio": undefined, - } - } - tooltip={ - Object { - "boundary": undefined, - "customTooltip": undefined, - "headerFormatter": [Function], - "type": "vertical", - } - } - /> - - - + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - ], - Array [ - Object { - "id": "string", + "markSizeRatio": undefined, + } + } + tooltip={ + Object { + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + - - - + + +
    +`; + +exports[`XYChart component split chart should render split chart if splitRowAccessor is specified 1`] = ` +
    + + + + } + onBrushEnd={[Function]} + onElementClick={[Function]} + onPointerUpdate={[Function]} + onRenderChange={[Function]} + rotation={0} + showLegend={false} + showLegendExtra={false} + theme={ + Object { + "background": Object { + "color": undefined, + }, + "barSeriesStyle": Object {}, + "chartMargins": Object {}, + "legend": Object { + "labelOptions": Object { + "maxLines": 0, }, }, - }, + "markSizeRatio": undefined, + } + } + tooltip={ Object { - "type": "return", - "value": Object { - "convert": [MockFunction] { - "calls": Array [ - Array [ - 1652034840000, - ], - Array [ - 1652122440000, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": 1652034840000, - }, - Object { - "type": "return", - "value": 1652122440000, + "boundary": undefined, + "customTooltip": undefined, + "headerFormatter": [Function], + "type": "vertical", + } + } + /> + + + + + + - + ] + } + /> + + +
    `; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx b/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx index 35e4c0c7f1abb2..035faf8d22b003 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/data_layers.tsx @@ -16,13 +16,12 @@ import React, { FC } from 'react'; import { PaletteRegistry } from '@kbn/coloring'; import { FormatFactory } from '@kbn/field-formats-plugin/common'; import { getAccessorByDimension } from '@kbn/visualizations-plugin/common/utils'; - +import { PersistedState } from '@kbn/visualizations-plugin/public'; import { CommonXYDataLayerConfig, EndValue, FittingFunction, ValueLabelMode, - XYCurveType, XScaleType, } from '../../common'; import { SeriesTypes, ValueLabelModes, AxisModes } from '../../common/constants'; @@ -42,7 +41,6 @@ interface Props { formatFactory: FormatFactory; chartHasMoreThanOneBarSeries?: boolean; yAxesConfiguration: GroupsConfiguration; - curveType?: XYCurveType; fittingFunction?: FittingFunction; endValue?: EndValue | undefined; paletteService: PaletteRegistry; @@ -55,6 +53,8 @@ interface Props { valueLabels: ValueLabelMode; defaultXScaleType: XScaleType; fieldFormats: LayersFieldFormats; + uiState?: PersistedState; + singleTable?: boolean; } export const DataLayers: FC = ({ @@ -62,7 +62,6 @@ export const DataLayers: FC = ({ layers, endValue, timeZone, - curveType, syncColors, valueLabels, fillOpacity, @@ -76,14 +75,57 @@ export const DataLayers: FC = ({ chartHasMoreThanOneBarSeries, defaultXScaleType, fieldFormats, + uiState, + singleTable, }) => { - const colorAssignments = getColorAssignments(layers, titles, fieldFormats, formattedDatatables); + // for singleTable mode we should use y accessors from all layers for creating correct series name and getting color + const allYAccessors = layers.flatMap((layer) => layer.accessors); + const allColumnsToLabel = layers.reduce((acc, layer) => { + if (layer.columnToLabel) { + return { ...acc, ...JSON.parse(layer.columnToLabel) }; + } + + return acc; + }, {}); + const allYTitles = Object.keys(titles).reduce((acc, key) => { + if (titles[key].yTitles) { + return { ...acc, ...titles[key].yTitles }; + } + return acc; + }, {}); + const colorAssignments = singleTable + ? getColorAssignments( + [ + { + ...layers[0], + layerId: 'commonLayerId', + accessors: allYAccessors, + columnToLabel: JSON.stringify(allColumnsToLabel), + }, + ], + { commonLayerId: { ...titles, yTitles: allYTitles } }, + { commonLayerId: fieldFormats[layers[0].layerId] }, + { commonLayerId: formattedDatatables[layers[0].layerId] } + ) + : getColorAssignments(layers, titles, fieldFormats, formattedDatatables); return ( <> - {layers.flatMap((layer) => - layer.accessors.map((accessor, accessorIndex) => { - const { seriesType, columnToLabel, layerId, table } = layer; - const yColumnId = getAccessorByDimension(accessor, table.columns); + {layers.flatMap((layer) => { + const yPercentileAccessors: string[] = []; + const yAccessors: string[] = []; + layer.accessors.forEach((accessor) => { + const columnId = getAccessorByDimension(accessor, layer.table.columns); + if (columnId.includes('.')) { + yPercentileAccessors.push(columnId); + } else { + yAccessors.push(columnId); + } + }); + return ( + yPercentileAccessors.length ? [...yAccessors, yPercentileAccessors] : [...yAccessors] + ).map((accessor, accessorIndex) => { + const { seriesType, columnToLabel, layerId } = layer; + const yColumnId = Array.isArray(accessor) ? accessor[0] : accessor; const columnToLabelMap: Record = columnToLabel ? JSON.parse(columnToLabel) : {}; @@ -104,7 +146,7 @@ export const DataLayers: FC = ({ const seriesProps = getSeriesProps({ layer, titles: titles[layer.layerId], - accessor: yColumnId, + accessor, chartHasMoreThanOneBarSeries, colorAssignments, formatFactory, @@ -118,11 +160,14 @@ export const DataLayers: FC = ({ fillOpacity, defaultXScaleType, fieldFormats, + uiState, + allYAccessors, + singleTable, }); const index = `${layer.layerId}-${accessorIndex}`; - const curve = curveType ? CurveType[curveType] : undefined; + const curve = layer.curveType ? CurveType[layer.curveType] : undefined; switch (seriesType) { case SeriesTypes.LINE: @@ -161,8 +206,8 @@ export const DataLayers: FC = ({ /> ); } - }) - )} + }); + })} ); }; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx index e27bb716c35c79..0d1d3b5b592569 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_action.tsx @@ -24,7 +24,8 @@ export const getLegendAction = ( onFilter: (data: FilterEvent['data']) => void, fieldFormats: LayersFieldFormats, formattedDatatables: DatatablesWithFormatInfo, - titles: LayersAccessorsTitles + titles: LayersAccessorsTitles, + singleTable?: boolean ): LegendAction => React.memo(({ series: [xySeries] }) => { const series = xySeries as XYChartSeriesIdentifier; @@ -35,6 +36,7 @@ export const getLegendAction = ( ) ) ); + const allYAccessors = dataLayers.flatMap((dataLayer) => dataLayer.accessors); if (layerIndex === -1) { return null; @@ -78,7 +80,7 @@ export const getLegendAction = ( series, { splitAccessors: layer.splitAccessors, - accessorsCount: layer.accessors.length, + accessorsCount: singleTable ? allYAccessors.length : layer.accessors.length, columns: table.columns, splitAccessorsFormats: fieldFormats[layer.layerId].splitSeriesAccessors, alreadyFormattedColumns: formattedDatatables[layer.layerId].formattedColumns, diff --git a/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx b/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx new file mode 100644 index 00000000000000..3573fc65e52884 --- /dev/null +++ b/src/plugins/chart_expressions/expression_xy/public/components/legend_color_picker.tsx @@ -0,0 +1,142 @@ +/* + * 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, { createContext, useCallback, useContext } from 'react'; +import { LegendColorPicker, Position, XYChartSeriesIdentifier } from '@elastic/charts'; +import { PopoverAnchorPosition, EuiWrappingPopover, EuiOutsideClickDetector } from '@elastic/eui'; +import type { PersistedState } from '@kbn/visualizations-plugin/public'; +import { ColorPicker } from '@kbn/charts-plugin/public'; +import { + DatatablesWithFormatInfo, + getMetaFromSeriesId, + getSeriesName, + LayersAccessorsTitles, + LayersFieldFormats, +} from '../helpers'; +import type { CommonXYDataLayerConfig } from '../../common/types'; + +const KEY_CODE_ENTER = 13; + +function getAnchorPosition(legendPosition: Position): PopoverAnchorPosition { + switch (legendPosition) { + case Position.Bottom: + return 'upCenter'; + case Position.Top: + return 'downCenter'; + case Position.Left: + return 'rightCenter'; + default: + return 'leftCenter'; + } +} + +export interface LegendColorPickerWrapperContextType { + legendPosition: Position; + setColor: (newColor: string | null, seriesKey: string | number) => void; + uiState?: PersistedState; + dataLayers: CommonXYDataLayerConfig[]; + formattedDatatables: DatatablesWithFormatInfo; + titles: LayersAccessorsTitles; + fieldFormats: LayersFieldFormats; + singleTable?: boolean; +} + +export const LegendColorPickerWrapperContext = createContext< + LegendColorPickerWrapperContextType | undefined +>(undefined); + +export const LegendColorPickerWrapper: LegendColorPicker = ({ + anchor, + color, + onClose, + onChange, + seriesIdentifiers: [seriesIdentifier], +}) => { + const colorPickerWrappingContext = useContext(LegendColorPickerWrapperContext); + const handleOutsideClick = useCallback(() => { + onClose?.(); + }, [onClose]); + + if (!colorPickerWrappingContext) { + return null; + } + + const { + legendPosition, + setColor, + uiState, + dataLayers, + titles, + formattedDatatables, + fieldFormats, + singleTable, + } = colorPickerWrappingContext; + const { layerId } = getMetaFromSeriesId(seriesIdentifier.specId); + + const layer = dataLayers.find((dataLayer) => dataLayer.layerId === layerId); + const allYAccessors = dataLayers.flatMap((dataLayer) => dataLayer.accessors); + const seriesName = layer + ? getSeriesName( + seriesIdentifier as XYChartSeriesIdentifier, + { + splitAccessors: layer.splitAccessors ?? [], + accessorsCount: singleTable ? allYAccessors.length : layer.accessors.length, + columns: formattedDatatables[layer.layerId].table.columns, + splitAccessorsFormats: fieldFormats[layer.layerId].splitSeriesAccessors, + alreadyFormattedColumns: formattedDatatables[layer.layerId].formattedColumns, + columnToLabelMap: layer.columnToLabel ? JSON.parse(layer.columnToLabel) : {}, + }, + titles[layer.layerId] + )?.toString() || '' + : ''; + + const overwriteColors: Record = uiState?.get('vis.colors', {}) ?? {}; + const colorIsOverwritten = seriesName.toString() in overwriteColors; + let keyDownEventOn = false; + + const handleChange = (newColor: string | null) => { + if (newColor) { + onChange(newColor); + } + setColor(newColor, seriesName); + // close the popover if no color is applied or the user has clicked a color + if (!newColor || !keyDownEventOn) { + onClose(); + } + }; + + const onKeyDown = (e: React.KeyboardEvent) => { + if (e.keyCode === KEY_CODE_ENTER) { + onClose?.(); + } + keyDownEventOn = true; + }; + + return ( + + + + + + ); +}; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/reference_lines/utils.tsx b/src/plugins/chart_expressions/expression_xy/public/components/reference_lines/utils.tsx index 2ccf2890efd490..5a4b145a6b1f6c 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/reference_lines/utils.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/reference_lines/utils.tsx @@ -72,6 +72,13 @@ export const getSharedStyle = (config: ReferenceLineAnnotationConfig) => ({ ? [(config.lineWidth || 1) * 3, config.lineWidth || 1] : config.lineStyle === 'dotted' ? [config.lineWidth || 1, config.lineWidth || 1] + : config.lineStyle === 'dot-dashed' + ? [ + (config.lineWidth || 1) * 5, + config.lineWidth || 1, + config.lineWidth || 1, + config.lineWidth || 1, + ] : undefined, }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/split_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/split_chart.tsx index 3f7d59e0473d5b..3487b89fff2900 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/split_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/split_chart.tsx @@ -9,41 +9,19 @@ import React, { useCallback } from 'react'; import { GroupBy, SmallMultiples, Predicate } from '@elastic/charts'; import { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; -import { - getAccessorByDimension, - getColumnByAccessor, -} from '@kbn/visualizations-plugin/common/utils'; +import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; import { Datatable } from '@kbn/expressions-plugin/public'; -import { SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; -import { FormatFactory } from '../types'; interface SplitChartProps { splitColumnAccessor?: ExpressionValueVisDimension | string; splitRowAccessor?: ExpressionValueVisDimension | string; columns: Datatable['columns']; - formatFactory: FormatFactory; - fieldFormats: Record; } const SPLIT_COLUMN = '__split_column__'; const SPLIT_ROW = '__split_row__'; -export const SplitChart = ({ - splitColumnAccessor, - splitRowAccessor, - columns, - fieldFormats, - formatFactory, -}: SplitChartProps) => { - const format = useCallback( - (value: unknown, accessor: ExpressionValueVisDimension | string) => { - const formatParams = fieldFormats[getAccessorByDimension(accessor, columns)]; - const formatter = formatFactory(formatParams); - return formatter.convert(value); - }, - [columns, formatFactory, fieldFormats] - ); - +export const SplitChart = ({ splitColumnAccessor, splitRowAccessor, columns }: SplitChartProps) => { const getData = useCallback( (datum: Record, accessor: ExpressionValueVisDimension | string) => { const splitColumn = getColumnByAccessor(accessor, columns); @@ -59,7 +37,6 @@ export const SplitChart = ({ id={SPLIT_COLUMN} by={(spec, datum) => getData(datum, splitColumnAccessor)} sort={Predicate.DataIndex} - format={(value) => format(value, splitColumnAccessor)} /> )} {splitRowAccessor && ( @@ -67,12 +44,11 @@ export const SplitChart = ({ id={SPLIT_ROW} by={(spec, datum) => getData(datum, splitRowAccessor)} sort={Predicate.DataIndex} - format={(value) => format(value, splitRowAccessor)} /> )} ) : null; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.test.tsx index 26c1c7ff785a26..fa8638afc68d13 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.test.tsx @@ -31,14 +31,14 @@ const getSeriesIdentifier = ({ splitColumnAccessor?: string; seriesSplitAccessors: Map; }): XYChartSeriesIdentifier => ({ - specId: generateSeriesId({ layerId, xAccessor }, splitAccessors, yAccessor), + specId: generateSeriesId({ layerId }, splitAccessors, yAccessor, xAccessor), xAccessor: xAccessor ?? 'x', yAccessor: yAccessor ?? 'a', splitAccessors: seriesSplitAccessors, seriesKeys: [], key: '1', - smVerticalAccessorValue: splitColumnAccessor, - smHorizontalAccessorValue: splitRowAccessor, + smVerticalAccessorValue: splitRowAccessor, + smHorizontalAccessorValue: splitColumnAccessor, }); describe('Tooltip', () => { @@ -113,6 +113,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} + layers={[sampleLayer]} /> ); @@ -133,6 +134,7 @@ describe('Tooltip', () => { formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} xDomain={xDomain} + layers={[sampleLayer]} /> ); @@ -153,6 +155,7 @@ describe('Tooltip', () => { formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} xDomain={xDomain} + layers={[sampleLayer]} /> ); @@ -170,6 +173,7 @@ describe('Tooltip', () => { formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} xDomain={xDomain2} + layers={[sampleLayer]} /> ); @@ -188,6 +192,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} + layers={[sampleLayer]} /> ); @@ -213,6 +218,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} + layers={[sampleLayer]} /> ); @@ -240,6 +246,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} + layers={[sampleLayer]} /> ); @@ -268,6 +275,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor, splitRowAccessor }} + layers={[sampleLayer]} /> ); @@ -295,6 +303,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitColumnAccessor }} + layers={[sampleLayer]} /> ); @@ -322,6 +331,7 @@ describe('Tooltip', () => { formatFactory={formatFactory} formattedDatatables={{ [layerId]: { table: data, formattedColumns: {} } }} splitAccessors={{ splitRowAccessor }} + layers={[sampleLayer]} /> ); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx index 7ab7c9f549e244..6d4ba715dae0dd 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/tooltip/tooltip.tsx @@ -8,7 +8,9 @@ import { TooltipInfo, XYChartSeriesIdentifier } from '@elastic/charts'; import { FormatFactory } from '@kbn/field-formats-plugin/common'; +import { getAccessorByDimension } from '@kbn/visualizations-plugin/common/utils'; import React, { FC } from 'react'; +import { CommonXYDataLayerConfig } from '../../../common'; import { DatatablesWithFormatInfo, getMetaFromSeriesId, @@ -32,6 +34,7 @@ type Props = TooltipInfo & { splitRowAccessor?: string; splitColumnAccessor?: string; }; + layers: CommonXYDataLayerConfig[]; }; export const Tooltip: FC = ({ @@ -43,6 +46,7 @@ export const Tooltip: FC = ({ formattedDatatables, splitAccessors, xDomain, + layers, }) => { const pickedValue = values.find(({ isHighlighted }) => isHighlighted); @@ -52,10 +56,14 @@ export const Tooltip: FC = ({ const data: TooltipData[] = []; const seriesIdentifier = pickedValue.seriesIdentifier as XYChartSeriesIdentifier; - const { layerId, xAccessor, yAccessor } = getMetaFromSeriesId(seriesIdentifier.specId); - const { formattedColumns } = formattedDatatables[layerId]; + const { layerId, xAccessor, yAccessors } = getMetaFromSeriesId(seriesIdentifier.specId); + const { formattedColumns, table } = formattedDatatables[layerId]; const layerTitles = titles[layerId]; const layerFormats = fieldFormats[layerId]; + const markSizeAccessor = layers.find((layer) => layer.layerId === layerId)?.markSizeAccessor; + const markSizeColumnId = markSizeAccessor + ? getAccessorByDimension(markSizeAccessor, table.columns) + : undefined; let headerFormatter; if (header && xAccessor) { headerFormatter = formattedColumns[xAccessor] @@ -67,7 +75,9 @@ export const Tooltip: FC = ({ }); } - const tooltipYAccessor = yAccessor === seriesIdentifier.yAccessor ? yAccessor : null; + const tooltipYAccessor = yAccessors.includes(seriesIdentifier.yAccessor as string) + ? (seriesIdentifier.yAccessor as string) + : null; if (tooltipYAccessor) { const yFormatter = formatFactory(layerFormats.yAccessors[tooltipYAccessor]); data.push({ @@ -75,6 +85,12 @@ export const Tooltip: FC = ({ value: yFormatter ? yFormatter.convert(pickedValue.value) : `${pickedValue.value}`, }); } + if (markSizeColumnId && pickedValue.formattedMarkValue) { + data.push({ + label: layerTitles?.markSizeTitles?.[markSizeColumnId], + value: pickedValue.formattedMarkValue, + }); + } seriesIdentifier.splitAccessors.forEach((splitValue, key) => { const splitSeriesFormatter = formattedColumns[key] ? null @@ -87,21 +103,18 @@ export const Tooltip: FC = ({ if ( splitAccessors?.splitColumnAccessor && - seriesIdentifier.smVerticalAccessorValue !== undefined + seriesIdentifier.smHorizontalAccessorValue !== undefined ) { data.push({ label: layerTitles?.splitColumnTitles?.[splitAccessors?.splitColumnAccessor], - value: `${seriesIdentifier.smVerticalAccessorValue}`, + value: `${seriesIdentifier.smHorizontalAccessorValue}`, }); } - if ( - splitAccessors?.splitRowAccessor && - seriesIdentifier.smHorizontalAccessorValue !== undefined - ) { + if (splitAccessors?.splitRowAccessor && seriesIdentifier.smVerticalAccessorValue !== undefined) { data.push({ label: layerTitles?.splitRowTitles?.[splitAccessors?.splitRowAccessor], - value: `${seriesIdentifier.smHorizontalAccessorValue}`, + value: `${seriesIdentifier.smVerticalAccessorValue}`, }); } diff --git a/src/plugins/chart_expressions/expression_xy/public/components/x_domain.tsx b/src/plugins/chart_expressions/expression_xy/public/components/x_domain.tsx index e193eb9a91d3fe..d11bcb0bfe071a 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/x_domain.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/x_domain.tsx @@ -6,10 +6,11 @@ * Side Public License, v 1. */ -import { isUndefined, uniq } from 'lodash'; +import { isUndefined, uniq, find } from 'lodash'; import React from 'react'; import moment from 'moment'; -import { Endzones } from '@kbn/charts-plugin/public'; +import dateMath, { Unit } from '@kbn/datemath'; +import { Endzones, getAdjustedInterval } from '@kbn/charts-plugin/public'; import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { getAccessorByDimension, @@ -47,6 +48,8 @@ export const getXDomain = ( minInterval: number | undefined, isTimeViz: boolean, isHistogram: boolean, + hasBars: boolean, + timeZone: string, xExtent?: AxisExtentConfigResult ) => { const appliedTimeRange = getAppliedTimeRange(datatableUtilitites, layers)?.timeRange; @@ -62,7 +65,7 @@ export const getXDomain = ( ? { minInterval, min: NaN, max: NaN } : undefined; - if (isHistogram && isFullyQualified(baseDomain)) { + if ((isHistogram || isTimeViz) && isFullyQualified(baseDomain)) { if (xExtent && !isTimeViz) { return { extendedDomain: { @@ -76,7 +79,8 @@ export const getXDomain = ( const xValues = uniq( layers .flatMap(({ table, xAccessor }) => { - const accessor = xAccessor && getAccessorByDimension(xAccessor, table.columns); + const accessor = + xAccessor !== undefined ? getAccessorByDimension(xAccessor, table.columns) : undefined; return table.rows.map((row) => accessor && row[accessor] && row[accessor].valueOf()); }) .filter((v) => !isUndefined(v)) @@ -86,14 +90,25 @@ export const getXDomain = ( const lastXValue = xValues[xValues.length - 1]; const domainMin = Math.min(firstXValue, baseDomain.min); - const domainMaxValue = baseDomain.max - baseDomain.minInterval; - const domainMax = Math.max(domainMaxValue, lastXValue); + const domainMaxValue = Math.max(baseDomain.max - baseDomain.minInterval, lastXValue); + const domainMax = hasBars ? domainMaxValue : domainMaxValue + baseDomain.minInterval; + + const duration = moment.duration(baseDomain.minInterval); + const selectedUnit = find(dateMath.units, (u) => { + const value = duration.as(u); + return Number.isInteger(value); + }) as Unit; return { extendedDomain: { min: domainMin, max: domainMax, - minInterval: baseDomain.minInterval, + minInterval: getAdjustedInterval( + xValues, + duration.as(selectedUnit), + selectedUnit, + timeZone + ), }, baseDomain, }; diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx index 4de0f274697b0b..aa05c90d052f22 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.test.tsx @@ -421,7 +421,7 @@ describe('XYChart component', () => { expect(component.find(Settings).prop('xDomain')).toEqual({ // shortened to 24th midnight (elastic-charts automatically adds one min interval) - max: new Date('2021-04-24').valueOf(), + max: new Date('2021-04-25').valueOf(), // extended to 22nd midnight because of first bucket min: new Date('2021-04-22').valueOf(), minInterval: 24 * 60 * 60 * 1000, @@ -446,7 +446,7 @@ describe('XYChart component', () => { domainStart: new Date('2021-04-22T12:00:00.000Z').valueOf(), domainEnd: new Date('2021-04-24T12:00:00.000Z').valueOf(), domainMin: new Date('2021-04-22').valueOf(), - domainMax: new Date('2021-04-24').valueOf(), + domainMax: new Date('2021-04-25').valueOf(), }) ); }); @@ -3209,7 +3209,7 @@ describe('XYChart component', () => { const smallMultiples = splitChart.dive().find(SmallMultiples); expect(groupBy.at(0).prop('id')).toEqual(SPLIT_ROW); - expect(smallMultiples.prop('splitHorizontally')).toEqual(SPLIT_ROW); + expect(smallMultiples.prop('splitVertically')).toEqual(SPLIT_ROW); }); it('should render split chart if splitColumnAccessor is specified', () => { @@ -3235,7 +3235,7 @@ describe('XYChart component', () => { const smallMultiples = splitChart.dive().find(SmallMultiples); expect(groupBy.at(0).prop('id')).toEqual(SPLIT_COLUMN); - expect(smallMultiples.prop('splitVertically')).toEqual(SPLIT_COLUMN); + expect(smallMultiples.prop('splitHorizontally')).toEqual(SPLIT_COLUMN); }); it('should render split chart if both, splitRowAccessor and splitColumnAccessor are specified', () => { @@ -3267,8 +3267,8 @@ describe('XYChart component', () => { expect(groupBy.at(0).prop('id')).toEqual(SPLIT_COLUMN); expect(groupBy.at(1).prop('id')).toEqual(SPLIT_ROW); - expect(smallMultiples.prop('splitVertically')).toEqual(SPLIT_COLUMN); - expect(smallMultiples.prop('splitHorizontally')).toEqual(SPLIT_ROW); + expect(smallMultiples.prop('splitVertically')).toEqual(SPLIT_ROW); + expect(smallMultiples.prop('splitHorizontally')).toEqual(SPLIT_COLUMN); }); }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 5bb7f5d6f8c47a..c94eccaeed0ba8 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import React, { useCallback, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { css } from '@emotion/react'; import { Chart, Settings, @@ -29,9 +30,9 @@ import { } from '@elastic/charts'; import { IconType } from '@elastic/eui'; import { PaletteRegistry } from '@kbn/coloring'; -import { RenderMode } from '@kbn/expressions-plugin/common'; +import { Datatable, RenderMode } from '@kbn/expressions-plugin/common'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; +import { EmptyPlaceholder, LegendToggle } from '@kbn/charts-plugin/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; import { ChartsPluginSetup, ChartsPluginStart, useActiveCursor } from '@kbn/charts-plugin/public'; import { MULTILAYER_TIME_AXIS_STYLE } from '@kbn/charts-plugin/common'; @@ -43,6 +44,7 @@ import { DEFAULT_LEGEND_SIZE, LegendSizeToPixels, } from '@kbn/visualizations-plugin/common/constants'; +import { PersistedState } from '@kbn/visualizations-plugin/public'; import type { FilterEvent, BrushEvent, FormatFactory } from '../types'; import { isTimeChart } from '../../common/helpers'; import type { @@ -96,6 +98,7 @@ import { XYCurrentTime } from './xy_current_time'; import './xy_chart.scss'; import { TooltipHeader } from './tooltip'; +import { LegendColorPickerWrapperContext, LegendColorPickerWrapper } from './legend_color_picker'; declare global { interface Window { @@ -123,6 +126,7 @@ export type XYChartRenderProps = XYChartProps & { syncTooltips: boolean; eventAnnotationService: EventAnnotationServiceType; renderComplete: () => void; + uiState?: PersistedState; }; function getValueLabelsStyling(isHorizontal: boolean): { @@ -154,10 +158,29 @@ function getIconForSeriesType(layer: CommonXYDataLayerConfig): IconType { `${layer.seriesType}${layer.isHorizontal ? '_horizontal' : ''}${ layer.isPercentage ? '_percentage' : '' }${layer.isStacked ? '_stacked' : ''}` - )!.icon || 'empty' + )?.icon || 'empty' ); } +function createSplitPoint( + accessor: string | number, + value: string | number, + rows: Datatable['rows'], + table: Datatable +) { + const splitPointRowIndex = rows.findIndex((row) => { + return row[accessor] === value; + }); + if (splitPointRowIndex !== -1) { + return { + row: splitPointRowIndex, + column: table.columns.findIndex((column) => column.id === accessor), + value: table.rows[splitPointRowIndex][accessor], + table, + }; + } +} + export const XYChartReportable = React.memo(XYChart); export function XYChart({ @@ -176,6 +199,7 @@ export function XYChart({ syncTooltips, useLegacyTimeAxis, renderComplete, + uiState, }: XYChartRenderProps) { const { legend, @@ -190,6 +214,7 @@ export function XYChart({ xAxisConfig, splitColumnAccessor, splitRowAccessor, + singleTable, } = args; const chartRef = useRef(null); const chartTheme = chartsThemeService.useChartsTheme(); @@ -200,6 +225,49 @@ export function XYChart({ (hashMap, layer) => ({ ...hashMap, [layer.layerId]: layer }), {} ); + const chartHasMoreThanOneSeries = + filteredLayers.length > 1 || + filteredLayers.some((layer) => layer.accessors.length > 1) || + filteredLayers.some( + (layer) => isDataLayer(layer) && layer.splitAccessors && layer.splitAccessors.length + ); + + const getShowLegendDefault = useCallback(() => { + const legendStateDefault = + legend.isVisible && !legend.showSingleSeries ? chartHasMoreThanOneSeries : legend.isVisible; + return uiState?.get('vis.legendOpen', legendStateDefault) ?? legendStateDefault; + }, [chartHasMoreThanOneSeries, legend.isVisible, legend.showSingleSeries, uiState]); + + const [showLegend, setShowLegend] = useState(() => getShowLegendDefault()); + + useEffect(() => { + const legendShow = getShowLegendDefault(); + setShowLegend(legendShow); + }, [getShowLegendDefault]); + + const toggleLegend = useCallback(() => { + setShowLegend((value) => { + const newValue = !value; + uiState?.set?.('vis.legendOpen', newValue); + return newValue; + }); + }, [uiState]); + + const setColor = useCallback( + (newColor: string | null, seriesLabel: string | number) => { + const colors = uiState?.get('vis.colors') || {}; + if (colors[seriesLabel] === newColor || !newColor) { + delete colors[seriesLabel]; + } else { + colors[seriesLabel] = newColor; + } + uiState?.setSilent('vis.colors', null); + uiState?.set('vis.colors', colors); + uiState?.emit('reload'); + uiState?.emit('colorChanged'); + }, + [uiState] + ); const handleCursorUpdate = useActiveCursor(chartsActiveCursorService, chartRef, { datatables: filteredLayers.map(({ table }) => table), @@ -216,8 +284,9 @@ export function XYChart({ const dataLayers: CommonXYDataLayerConfig[] = filteredLayers.filter(isDataLayer); const formattedDatatables = useMemo( - () => getFormattedTablesByLayers(dataLayers, formatFactory), - [dataLayers, formatFactory] + () => + getFormattedTablesByLayers(dataLayers, formatFactory, splitColumnAccessor, splitRowAccessor), + [dataLayers, formatFactory, splitColumnAccessor, splitRowAccessor] ); const fieldFormats = useMemo( @@ -248,12 +317,6 @@ export function XYChart({ ? String(value) : String(xAxisFormatter.convert(value)); - const chartHasMoreThanOneSeries = - filteredLayers.length > 1 || - filteredLayers.some((layer) => layer.accessors.length > 1) || - filteredLayers.some( - (layer) => isDataLayer(layer) && layer.splitAccessors && layer.splitAccessors.length - ); const shouldRotate = isHorizontalChart(dataLayers); const yAxesConfiguration = getAxesConfiguration( @@ -272,7 +335,7 @@ export function XYChart({ [...(yAxisConfigs ?? []), ...(xAxisConfig ? [xAxisConfig] : [])] ); - const xTitle = xAxisConfig?.title || (xAxisColumn && xAxisColumn.name); + const xTitle = xAxisConfig?.title || (xAxisColumn && xAxisColumn.name) || undefined; const yAxesMap = { left: yAxesConfiguration.find( ({ position }) => position === getAxisPosition(Position.Left, shouldRotate) @@ -303,6 +366,7 @@ export function XYChart({ const defaultXScaleType = isTimeViz ? XScaleTypes.TIME : XScaleTypes.ORDINAL; const isHistogramViz = dataLayers.every((l) => l.isHistogram); + const hasBars = dataLayers.some((l) => l.seriesType === SeriesTypes.BAR); const { baseDomain: rawXDomain, extendedDomain: xDomain } = getXDomain( data.datatableUtilities, @@ -310,6 +374,8 @@ export function XYChart({ minInterval, isTimeViz, isHistogramViz, + hasBars, + timeZone, xAxisConfig?.extent ); @@ -411,14 +477,16 @@ export function XYChart({ }) ); - const fit = !hasBarOrArea && extent.mode === AxisExtentModes.DATA_BOUNDS; + const fit = Boolean( + (!hasBarOrArea || axis.extent?.enforce) && extent.mode === AxisExtentModes.DATA_BOUNDS + ); const padding = axis.boundsMargin || undefined; let min: number = NaN; let max: number = NaN; if (extent.mode === 'custom') { const { inclusiveZeroError, boundaryError } = validateExtent(hasBarOrArea, extent); - if (!inclusiveZeroError && !boundaryError) { + if ((!inclusiveZeroError && !boundaryError) || extent.enforce) { min = extent.lowerBound ?? NaN; max = extent.upperBound ?? NaN; } @@ -450,11 +518,12 @@ export function XYChart({ }; }; - const shouldShowValueLabels = - // No stacked bar charts - dataLayers.every((layer) => !layer.isStacked) && - // No histogram charts - !isHistogramViz; + const shouldShowValueLabels = uiState + ? valueLabels !== ValueLabelModes.HIDE + : // No stacked bar charts + dataLayers.every((layer) => !layer.isStacked) && + // No histogram charts + !isHistogramViz; const valueLabelsStyling = shouldShowValueLabels && @@ -514,21 +583,44 @@ export function XYChart({ if (xySeries.seriesKeys.length > 1) { xySeries.splitAccessors.forEach((value, accessor) => { - const splitPointRowIndex = formattedDatatables[layer.layerId].table.rows.findIndex( - (row) => { - return row[accessor] === value; - } + const point = createSplitPoint( + accessor, + value, + formattedDatatables[layer.layerId].table.rows, + table ); - if (splitPointRowIndex !== -1) { - splitPoints.push({ - row: splitPointRowIndex, - column: table.columns.findIndex((column) => column.id === accessor), - value: table.rows[splitPointRowIndex][accessor], - table, - }); + if (point) { + splitPoints.push(point); } }); } + + if (xySeries.smHorizontalAccessorValue && splitColumnAccessor) { + const accessor = getAccessorByDimension(splitColumnAccessor, table.columns); + const point = createSplitPoint( + accessor, + xySeries.smHorizontalAccessorValue, + formattedDatatables[layer.layerId].table.rows, + table + ); + if (point) { + splitPoints.push(point); + } + } + + if (xySeries.smVerticalAccessorValue && splitRowAccessor) { + const accessor = getAccessorByDimension(splitRowAccessor, table.columns); + const point = createSplitPoint( + accessor, + xySeries.smVerticalAccessorValue, + formattedDatatables[layer.layerId].table.rows, + table + ); + if (point) { + splitPoints.push(point); + } + } + const context: FilterEvent['data'] = { data: [...points, ...splitPoints], }; @@ -546,7 +638,9 @@ export function XYChart({ const { table } = dataLayers[0]; const xAccessor = - dataLayers[0].xAccessor && getAccessorByDimension(dataLayers[0].xAccessor, table.columns); + dataLayers[0].xAccessor !== undefined + ? getAccessorByDimension(dataLayers[0].xAccessor, table.columns) + : undefined; const xAxisColumnIndex = table.columns.findIndex((el) => el.id === xAccessor); const context: BrushEvent['data'] = { range: [min, max], table, column: xAxisColumnIndex }; @@ -617,248 +711,273 @@ export function XYChart({ splitRowAccessor && splitTable ? getAccessorByDimension(splitRowAccessor, splitTable?.columns) : undefined; - const splitLayerFieldFormats = fieldFormats[dataLayers[0].layerId]; - const splitFieldFormats = { - ...(splitColumnId - ? { [splitColumnId]: splitLayerFieldFormats.splitColumnAccessors[splitColumnId] } - : {}), - ...(splitRowId ? { [splitRowId]: splitLayerFieldFormats.splitRowAccessors[splitRowId] } : {}), - }; + + const chartContainerStyle = css({ + width: '100%', + height: '100%', + overflowX: 'hidden', + position: uiState ? 'absolute' : 'relative', + }); return ( - - - } - onRenderChange={onRenderChange} - onPointerUpdate={handleCursorUpdate} - externalPointerEvents={{ - tooltip: { visible: syncTooltips, placement: Placement.Right }, - }} - debugState={window._echDebugStateFlag ?? false} - showLegend={ - legend.isVisible && !legend.showSingleSeries - ? chartHasMoreThanOneSeries - : legend.isVisible - } - legendPosition={legend?.isInside ? legendInsideParams : legend.position} - legendSize={LegendSizeToPixels[legend.legendSize ?? DEFAULT_LEGEND_SIZE]} - theme={{ - ...chartTheme, - barSeriesStyle: { - ...chartTheme.barSeriesStyle, - ...valueLabelsStyling, - }, - background: { - color: undefined, // removes background for embeddables - }, - legend: { - labelOptions: { maxLines: legend.shouldTruncate ? legend?.maxLines ?? 1 : 0 }, - }, - // if not title or labels are shown for axes, add some padding if required by reference line markers - chartMargins: { - ...chartTheme.chartPaddings, - ...computeChartMargins( - linesPaddings, - { ...tickLabelsVisibilitySettings, x: xAxisConfig?.showLabels }, - { ...axisTitlesVisibilitySettings, x: xAxisConfig?.showTitle }, - yAxesMap, - shouldRotate - ), - }, - markSizeRatio: args.markSizeRatio, - }} - baseTheme={chartBaseTheme} - tooltip={{ - boundary: document.getElementById('app-fixed-viewport') ?? undefined, - headerFormatter: !args.detailedTooltip - ? ({ value }) => ( - - ) - : undefined, - customTooltip: args.detailedTooltip - ? ({ header, values }) => ( - - ) - : undefined, - type: args.showTooltip ? TooltipType.VerticalCursor : TooltipType.None, - }} - allowBrushingLastHistogramBin={isTimeViz} - rotation={shouldRotate ? 90 : 0} - xDomain={xDomain} - onBrushEnd={interactive ? (brushHandler as BrushEndListener) : undefined} - onElementClick={interactive ? clickHandler : undefined} - legendAction={ - interactive - ? getLegendAction(dataLayers, onClickValue, fieldFormats, formattedDatatables, titles) - : undefined - } - showLegendExtra={isHistogramViz && valuesInLegend} - ariaLabel={args.ariaLabel} - ariaUseDefaultSummary={!args.ariaLabel} - orderOrdinalBinsBy={ - args.orderBucketsBySum - ? { - direction: Direction.Descending, - } - : undefined - } - /> - - - { - let value = safeXAccessorLabelRenderer(d) || ''; - if (xAxisConfig?.truncate && value.length > xAxisConfig.truncate) { - value = `${value.slice(0, xAxisConfig.truncate)}...`; - } - return value; - }} - style={xAxisStyle} - showOverlappingLabels={xAxisConfig?.showOverlappingLabels} - showDuplicatedTicks={xAxisConfig?.showDuplicates} - timeAxisLayerCount={shouldUseNewTimeAxis ? 3 : 0} - /> - {isSplitChart && splitTable && ( - + {showLegend !== undefined && uiState && ( + )} - {yAxesConfiguration.map((axis) => { - return ( - + + + } + onRenderChange={onRenderChange} + onPointerUpdate={handleCursorUpdate} + externalPointerEvents={{ + tooltip: { visible: syncTooltips, placement: Placement.Right }, + }} + legendColorPicker={uiState ? LegendColorPickerWrapper : undefined} + debugState={window._echDebugStateFlag ?? false} + showLegend={showLegend} + legendPosition={legend?.isInside ? legendInsideParams : legend.position} + legendSize={LegendSizeToPixels[legend.legendSize ?? DEFAULT_LEGEND_SIZE]} + theme={{ + ...chartTheme, + barSeriesStyle: { + ...chartTheme.barSeriesStyle, + ...valueLabelsStyling, + }, + background: { + color: undefined, // removes background for embeddables + }, + legend: { + labelOptions: { maxLines: legend.shouldTruncate ? legend?.maxLines ?? 1 : 0 }, + }, + // if not title or labels are shown for axes, add some padding if required by reference line markers + chartMargins: { + ...chartTheme.chartPaddings, + ...computeChartMargins( + linesPaddings, + { ...tickLabelsVisibilitySettings, x: xAxisConfig?.showLabels }, + { ...axisTitlesVisibilitySettings, x: xAxisConfig?.showTitle }, + yAxesMap, + shouldRotate + ), + }, + markSizeRatio: args.markSizeRatio, + }} + baseTheme={chartBaseTheme} + tooltip={{ + boundary: document.getElementById('app-fixed-viewport') ?? undefined, + headerFormatter: !args.detailedTooltip + ? ({ value }) => ( + + ) + : undefined, + customTooltip: args.detailedTooltip + ? ({ header, values }) => ( + + ) + : undefined, + type: args.showTooltip ? TooltipType.VerticalCursor : TooltipType.None, }} - hide={axis.hide || dataLayers[0]?.simpleView} + allowBrushingLastHistogramBin={isTimeViz} + rotation={shouldRotate ? 90 : 0} + xDomain={xDomain} + onBrushEnd={interactive ? (brushHandler as BrushEndListener) : undefined} + onElementClick={interactive ? clickHandler : undefined} + legendAction={ + interactive + ? getLegendAction( + dataLayers, + onClickValue, + fieldFormats, + formattedDatatables, + titles, + singleTable + ) + : undefined + } + showLegendExtra={isHistogramViz && valuesInLegend} + ariaLabel={args.ariaLabel} + ariaUseDefaultSummary={!args.ariaLabel} + orderOrdinalBinsBy={ + args.orderBucketsBySum + ? { + direction: Direction.Descending, + } + : undefined + } + /> + + + { - let value = axis.formatter?.convert(d) || ''; - if (axis.truncate && value.length > axis.truncate) { - value = `${value.slice(0, axis.truncate)}...`; + let value = safeXAccessorLabelRenderer(d) || ''; + if (xAxisConfig?.truncate && value.length > xAxisConfig.truncate) { + value = `${value.slice(0, xAxisConfig.truncate)}...`; } return value; }} - style={getYAxesStyle(axis)} - domain={getYAxisDomain(axis)} - showOverlappingLabels={axis.showOverlappingLabels} - showDuplicatedTicks={axis.showDuplicates} - ticks={5} + style={xAxisStyle} + showOverlappingLabels={xAxisConfig?.showOverlappingLabels} + showDuplicatedTicks={xAxisConfig?.showDuplicates} + timeAxisLayerCount={shouldUseNewTimeAxis ? 3 : 0} /> - ); - })} - - {!hideEndzones && ( - - layer.isHistogram && - (layer.isStacked || !layer.splitAccessors || !layer.splitAccessors.length) && - (layer.isStacked || - layer.seriesType !== SeriesTypes.BAR || - !chartHasMoreThanOneBarSeries) + {isSplitChart && splitTable && ( + + )} + {yAxesConfiguration.map((axis) => { + return ( + { + let value = axis.formatter?.convert(d) || ''; + if (axis.truncate && value.length > axis.truncate) { + value = `${value.slice(0, axis.truncate)}...`; + } + return value; + }} + style={getYAxesStyle(axis)} + domain={getYAxisDomain(axis)} + showOverlappingLabels={axis.showOverlappingLabels} + showDuplicatedTicks={axis.showDuplicates} + /> + ); + })} + + {!hideEndzones && ( + + layer.isHistogram && + (layer.isStacked || !layer.splitAccessors || !layer.splitAccessors.length) && + (layer.isStacked || + layer.seriesType !== SeriesTypes.BAR || + !chartHasMoreThanOneBarSeries) + )} + /> )} - /> - )} - {dataLayers.length && ( - - )} - {referenceLineLayers.length ? ( - - ) : null} - {rangeAnnotations.length || groupedLineAnnotations.length ? ( - 0} - minInterval={minInterval} - simpleView={annotationsLayers?.[0].simpleView} - outsideDimension={ - rangeAnnotations.length && shouldHideDetails - ? OUTSIDE_RECT_ANNOTATION_WIDTH_SUGGESTION - : shouldUseNewTimeAxis - ? Number(MULTILAYER_TIME_AXIS_STYLE.tickLine?.padding || 0) + - Number(chartTheme.axes?.tickLabel?.fontSize || 0) - : Number(chartTheme.axes?.tickLine?.size) || OUTSIDE_RECT_ANNOTATION_WIDTH - } - /> - ) : null} - + {dataLayers.length && ( + + )} + {referenceLineLayers.length ? ( + + ) : null} + {rangeAnnotations.length || groupedLineAnnotations.length ? ( + 0} + minInterval={minInterval} + simpleView={annotationsLayers?.[0].simpleView} + outsideDimension={ + rangeAnnotations.length && shouldHideDetails + ? OUTSIDE_RECT_ANNOTATION_WIDTH_SUGGESTION + : shouldUseNewTimeAxis + ? Number(MULTILAYER_TIME_AXIS_STYLE.tickLine?.padding || 0) + + Number(chartTheme.axes?.tickLabel?.fontSize || 0) + : Number(chartTheme.axes?.tickLine?.size) || OUTSIDE_RECT_ANNOTATION_WIDTH + } + /> + ) : null} + + + ); } diff --git a/src/plugins/chart_expressions/expression_xy/public/definitions/visualizations.ts b/src/plugins/chart_expressions/expression_xy/public/definitions/visualizations.ts index d16d8204846fcd..bb4acd7fa50de3 100644 --- a/src/plugins/chart_expressions/expression_xy/public/definitions/visualizations.ts +++ b/src/plugins/chart_expressions/expression_xy/public/definitions/visualizations.ts @@ -28,6 +28,7 @@ export const visualizationDefinitions = [ { id: `${SeriesTypes.BAR}_horizontal_stacked`, icon: BarHorizontalStackedIcon }, { id: `${SeriesTypes.BAR}_horizontal_percentage_stacked`, icon: BarHorizontalPercentageIcon }, { id: SeriesTypes.LINE, icon: LineIcon }, + { id: `${SeriesTypes.LINE}_stacked`, icon: LineIcon }, { id: SeriesTypes.AREA, icon: AreaIcon }, { id: `${SeriesTypes.AREA}_stacked`, icon: AreaStackedIcon }, { id: `${SeriesTypes.AREA}_percentage_stacked`, icon: AreaPercentageIcon }, diff --git a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx index e1b5512dbebffd..3bab1c2a1accd4 100644 --- a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx @@ -9,10 +9,12 @@ import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n-react'; import { ThemeServiceStart } from '@kbn/core/public'; +import { css } from '@emotion/react'; import React from 'react'; import ReactDOM from 'react-dom'; import { METRIC_TYPE } from '@kbn/analytics'; import type { PaletteRegistry } from '@kbn/coloring'; +import { PersistedState } from '@kbn/visualizations-plugin/public'; import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; @@ -133,13 +135,16 @@ export const getXyChartRenderer = ({ import('../helpers/interval'), ]); + const chartContainerStyle = css({ + position: 'relative', + width: '100%', + height: '100%', + }); + ReactDOM.render( -
    +
    {' '} diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.test.ts b/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.test.ts index f1a11bbe06185b..6442845b0ecf3b 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.test.ts +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.test.ts @@ -118,21 +118,28 @@ describe('color_assignment', () => { }, }; + const titles = { + [layers[0].layerId]: { + yTitles: { + y1: 'test1', + y2: 'test2', + y3: 'test3', + y4: 'test4', + }, + }, + [layers[1].layerId]: { + yTitles: { + y1: 'test1', + y2: 'test2', + y3: 'test3', + y4: 'test4', + }, + }, + }; + describe('totalSeriesCount', () => { it('should calculate total number of series per palette', () => { - const assignments = getColorAssignments( - layers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, - fieldFormats, - formattedDatatables - ); + const assignments = getColorAssignments(layers, titles, fieldFormats, formattedDatatables); // two y accessors, with 3 splitted series expect(assignments.palette1.totalSeriesCount).toEqual(2 * 3); expect(assignments.palette2.totalSeriesCount).toEqual(2 * 3); @@ -141,14 +148,7 @@ describe('color_assignment', () => { it('should calculate total number of series spanning multible layers', () => { const assignments = getColorAssignments( [layers[0], { ...layers[1], palette: layers[0].palette }], - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, formattedDatatables ); @@ -160,14 +160,7 @@ describe('color_assignment', () => { it('should calculate total number of series for non split series', () => { const assignments = getColorAssignments( [layers[0], { ...layers[1], palette: layers[0].palette, splitAccessors: undefined }], - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, formattedDatatables ); @@ -200,14 +193,7 @@ describe('color_assignment', () => { const assignments = getColorAssignments( newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, newFormattedDatatables ); @@ -230,14 +216,7 @@ describe('color_assignment', () => { }; const assignments = getColorAssignments( newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, newFormattedDatatables ); @@ -249,44 +228,20 @@ describe('color_assignment', () => { describe('getRank', () => { it('should return the correct rank for a series key', () => { - const assignments = getColorAssignments( - layers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, - fieldFormats, - formattedDatatables - ); + const assignments = getColorAssignments(layers, titles, fieldFormats, formattedDatatables); // 3 series in front of 2/y2 - 1/y1, 1/y2 and 2/y1 - expect(assignments.palette1.getRank(layers[0], '2 - test2')).toEqual(3); + expect(assignments.palette1.getRank(layers[0].layerId, '2 - test2')).toEqual(3); // 1 series in front of 1/y4 - 1/y3 - expect(assignments.palette2.getRank(layers[1], '1 - test4')).toEqual(1); + expect(assignments.palette2.getRank(layers[1].layerId, '1 - test4')).toEqual(1); }); it('should return the correct rank for a series key spanning multiple layers', () => { const newLayers = [layers[0], { ...layers[1], palette: layers[0].palette }]; - const assignments = getColorAssignments( - newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, - fieldFormats, - formattedDatatables - ); + const assignments = getColorAssignments(newLayers, titles, fieldFormats, formattedDatatables); // 3 series in front of 2/y2 - 1/y1, 1/y2 and 2/y1 - expect(assignments.palette1.getRank(newLayers[0], '2 - test2')).toEqual(3); + expect(assignments.palette1.getRank(newLayers[0].layerId, '2 - test2')).toEqual(3); // 2 series in front for the current layer (1/y3, 1/y4), plus all 6 series from the first layer - expect(assignments.palette1.getRank(newLayers[1], '2 - test3')).toEqual(8); + expect(assignments.palette1.getRank(newLayers[1].layerId, '2 - test3')).toEqual(8); }); it('should return the correct rank for a series without a split', () => { @@ -294,23 +249,11 @@ describe('color_assignment', () => { layers[0], { ...layers[1], palette: layers[0].palette, splitAccessors: undefined }, ]; - const assignments = getColorAssignments( - newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, - fieldFormats, - formattedDatatables - ); + const assignments = getColorAssignments(newLayers, titles, fieldFormats, formattedDatatables); // 3 series in front of 2/y2 - 1/y1, 1/y2 and 2/y1 - expect(assignments.palette1.getRank(newLayers[0], '2 - test2')).toEqual(3); + expect(assignments.palette1.getRank(newLayers[0].layerId, '2 - test2')).toEqual(3); // 1 series in front for the current layer (y3), plus all 6 series from the first layer - expect(assignments.palette1.getRank(newLayers[1], 'test4')).toEqual(7); + expect(assignments.palette1.getRank(newLayers[1].layerId, 'test4')).toEqual(7); }); it('should return the correct rank for a series with a non-primitive value', () => { @@ -336,21 +279,14 @@ describe('color_assignment', () => { const assignments = getColorAssignments( newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, newFormattedDatatables ); fieldFormats.first.splitSeriesAccessors.split1.formatter.convert = (x) => x as string; // 3 series in front of (complex object)/y1 - abc/y1, abc/y2 - expect(assignments.palette1.getRank(layers[0], 'formatted - test1')).toEqual(2); + expect(assignments.palette1.getRank(layers[0].layerId, 'formatted - test1')).toEqual(2); }); it('should handle missing columns', () => { @@ -365,20 +301,13 @@ describe('color_assignment', () => { const assignments = getColorAssignments( newLayers, - { - yTitles: { - y1: 'test1', - y2: 'test2', - y3: 'test3', - y4: 'test4', - }, - }, + titles, fieldFormats, newFormattedDatatables ); // if the split column is missing, assume it is the first splitted series. One series in front - 0/y1 - expect(assignments.palette1.getRank(layers[0], 'test2')).toEqual(1); + expect(assignments.palette1.getRank(layers[0].layerId, 'test2')).toEqual(1); }); }); }); diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.ts b/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.ts index c7139cf036fa21..2cce918d4b7984 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.ts +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/color_assignment.ts @@ -13,7 +13,12 @@ import { getAccessorByDimension } from '@kbn/visualizations-plugin/common/utils' import type { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common'; import { isDataLayer } from './visualization'; import { CommonXYDataLayerConfig, CommonXYLayerConfig } from '../../common'; -import { LayerAccessorsTitles, LayerFieldFormats, LayersFieldFormats } from './layers'; +import { + LayerAccessorsTitles, + LayerFieldFormats, + LayersAccessorsTitles, + LayersFieldFormats, +} from './layers'; import { DatatablesWithFormatInfo, DatatableWithFormatInfo } from './data_layers'; export const defaultReferenceLineColor = euiLightVars.euiColorDarkShade; @@ -22,7 +27,7 @@ export type ColorAssignments = Record< string, { totalSeriesCount: number; - getRank(sortedLayer: CommonXYDataLayerConfig, seriesName: string): number; + getRank(layerId: string, seriesName: string): number; } >; @@ -53,7 +58,8 @@ export const getAllSeries = ( accessors: Array, columnToLabel: CommonXYDataLayerConfig['columnToLabel'], titles: LayerAccessorsTitles, - fieldFormats: LayerFieldFormats + fieldFormats: LayerFieldFormats, + accessorsCount: number ) => { if (!formattedDatatable.table) { return []; @@ -71,7 +77,7 @@ export const getAllSeries = ( const yTitle = columnToLabelMap[yAccessor] ?? titles?.yTitles?.[yAccessor] ?? null; let name = yTitle; if (splitName) { - name = accessors.length > 1 ? `${splitName} - ${yTitle}` : splitName; + name = accessorsCount > 1 ? `${splitName} - ${yTitle}` : splitName; } if (!allSeries.includes(name)) { @@ -85,7 +91,7 @@ export const getAllSeries = ( export function getColorAssignments( layers: CommonXYLayerConfig[], - titles: LayerAccessorsTitles, + titles: LayersAccessorsTitles, fieldFormats: LayersFieldFormats, formattedDatatables: DatatablesWithFormatInfo ): ColorAssignments { @@ -111,22 +117,22 @@ export function getColorAssignments( layer.splitAccessors, layer.accessors, layer.columnToLabel, - titles, - fieldFormats[layer.layerId] + titles[layer.layerId], + fieldFormats[layer.layerId], + layer.accessors.length ) || []; return { numberOfSeries: allSeries.length, allSeries }; }); + const totalSeriesCount = seriesPerLayer.reduce( (sum, perLayer) => sum + perLayer.numberOfSeries, 0 ); return { totalSeriesCount, - getRank(sortedLayer: CommonXYDataLayerConfig, seriesName: string) { - const layerIndex = paletteLayers.findIndex( - (layer) => sortedLayer.layerId === layer.layerId - ); + getRank(layerId: string, seriesName: string) { + const layerIndex = paletteLayers.findIndex((layer) => layerId === layer.layerId); const currentSeriesPerLayer = seriesPerLayer[layerIndex]; const rank = currentSeriesPerLayer.allSeries.indexOf(seriesName); return ( diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx index 4f830c08b234d8..8098bb0efe02b2 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/data_layers.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { IFieldFormat } from '@kbn/field-formats-plugin/common'; +import type { PersistedState } from '@kbn/visualizations-plugin/public'; import { Datatable } from '@kbn/expressions-plugin/common'; import { getAccessorByDimension } from '@kbn/visualizations-plugin/common/utils'; import type { ExpressionValueVisDimension } from '@kbn/visualizations-plugin/common/expression_functions'; @@ -37,7 +38,7 @@ type SeriesSpec = LineSeriesProps & BarSeriesProps & AreaSeriesProps; type GetSeriesPropsFn = (config: { layer: CommonXYDataLayerConfig; titles?: LayerAccessorsTitles; - accessor: string; + accessor: string | string[]; chartHasMoreThanOneBarSeries?: boolean; formatFactory: FormatFactory; colorAssignments: ColorAssignments; @@ -51,6 +52,9 @@ type GetSeriesPropsFn = (config: { formattedDatatableInfo: DatatableWithFormatInfo; defaultXScaleType: XScaleType; fieldFormats: LayersFieldFormats; + uiState?: PersistedState; + allYAccessors: Array; + singleTable?: boolean; }) => SeriesSpec; type GetSeriesNameFn = ( @@ -70,12 +74,13 @@ type GetColorFn = ( seriesIdentifier: XYChartSeriesIdentifier, config: { layer: CommonXYDataLayerConfig; - accessor: string; colorAssignments: ColorAssignments; paletteService: PaletteRegistry; getSeriesNameFn: (d: XYChartSeriesIdentifier) => SeriesName; syncColors?: boolean; - } + }, + uiState?: PersistedState, + singleTable?: boolean ) => string | null; type GetPointConfigFn = (config: { @@ -107,6 +112,8 @@ export const getFormattedRow = ( columns: Datatable['columns'], columnsFormatters: Record, xAccessor: string | undefined, + splitColumnAccessor: string | undefined, + splitRowAccessor: string | undefined, xScaleType: XScaleType ): { row: Datatable['rows'][number]; formattedColumns: Record } => columns.reduce( @@ -115,7 +122,10 @@ export const getFormattedRow = ( if ( record != null && // pre-format values for ordinal x axes because there can only be a single x axis formatter on chart level - (!isPrimitive(record) || (id === xAccessor && xScaleType === 'ordinal')) + (!isPrimitive(record) || + (id === xAccessor && xScaleType === 'ordinal') || + id === splitColumnAccessor || + id === splitRowAccessor) ) { return { row: { ...formattedInfo.row, [id]: columnsFormatters[id]!.convert(record) }, @@ -131,6 +141,8 @@ export const getFormattedTable = ( table: Datatable, formatFactory: FormatFactory, xAccessor: string | ExpressionValueVisDimension | undefined, + splitColumnAccessor: string | ExpressionValueVisDimension | undefined, + splitRowAccessor: string | ExpressionValueVisDimension | undefined, accessors: Array, xScaleType: XScaleType ): { table: Datatable; formattedColumns: Record } => { @@ -161,6 +173,8 @@ export const getFormattedTable = ( table.columns, columnsFormatters, xAccessor ? getAccessorByDimension(xAccessor, table.columns) : undefined, + splitColumnAccessor ? getAccessorByDimension(splitColumnAccessor, table.columns) : undefined, + splitRowAccessor ? getAccessorByDimension(splitRowAccessor, table.columns) : undefined, xScaleType ); formattedTableInfo.rows.push(formattedRowInfo.row); @@ -178,7 +192,9 @@ export const getFormattedTable = ( export const getFormattedTablesByLayers = ( layers: CommonXYDataLayerConfig[], - formatFactory: FormatFactory + formatFactory: FormatFactory, + splitColumnAccessor?: string | ExpressionValueVisDimension, + splitRowAccessor?: string | ExpressionValueVisDimension ): DatatablesWithFormatInfo => layers.reduce( ( @@ -190,9 +206,11 @@ export const getFormattedTablesByLayers = ( table, formatFactory, xAccessor, - [xAccessor, ...splitAccessors, ...accessors].filter( - (a): a is string | ExpressionValueVisDimension => a !== undefined - ), + splitColumnAccessor, + splitRowAccessor, + [xAccessor, ...splitAccessors, ...accessors, splitColumnAccessor, splitRowAccessor].filter< + string | ExpressionValueVisDimension + >((a): a is string | ExpressionValueVisDimension => a !== undefined), xScaleType ), }), @@ -290,21 +308,29 @@ const getLineConfig: GetLineConfigFn = ({ showLines, lineWidth }) => ({ const getColor: GetColorFn = ( series, - { layer, accessor, colorAssignments, paletteService, syncColors, getSeriesNameFn } + { layer, colorAssignments, paletteService, syncColors, getSeriesNameFn }, + uiState, + singleTable ) => { - const overwriteColor = getSeriesColor(layer, accessor); + const overwriteColor = getSeriesColor(layer, series.yAccessor as string); if (overwriteColor !== null) { return overwriteColor; } - const colorAssignment = colorAssignments[layer.palette.name]; const name = getSeriesNameFn(series)?.toString() || ''; + const overwriteColors: Record = uiState?.get ? uiState.get('vis.colors', {}) : {}; + + if (Object.keys(overwriteColors).includes(name)) { + return overwriteColors[name]; + } + const colorAssignment = colorAssignments[layer.palette.name]; + const seriesLayers: SeriesLayer[] = [ { name, totalSeriesAtDepth: colorAssignment.totalSeriesCount, - rankAtDepth: colorAssignment.getRank(layer, name), + rankAtDepth: colorAssignment.getRank(singleTable ? 'commonLayerId' : layer.layerId, name), }, ]; return paletteService.get(layer.palette.name).getCategoricalColor( @@ -320,23 +346,25 @@ const getColor: GetColorFn = ( }; const EMPTY_ACCESSOR = '-'; -const SPLIT_CHAR = '.'; +const SPLIT_CHAR = ':'; +const SPLIT_Y_ACCESSORS = '|'; export const generateSeriesId = ( - { layerId, xAccessor }: Pick, + { layerId }: Pick, splitColumnIds: string[], - accessor?: string + accessor?: string, + xColumnId?: string ) => - [layerId, xAccessor ?? EMPTY_ACCESSOR, accessor ?? EMPTY_ACCESSOR, ...splitColumnIds].join( + [layerId, xColumnId ?? EMPTY_ACCESSOR, accessor ?? EMPTY_ACCESSOR, ...splitColumnIds].join( SPLIT_CHAR ); export const getMetaFromSeriesId = (seriesId: string) => { - const [layerId, xAccessor, yAccessor, ...splitAccessors] = seriesId.split(SPLIT_CHAR); + const [layerId, xAccessor, yAccessors, ...splitAccessors] = seriesId.split(SPLIT_CHAR); return { layerId, xAccessor: xAccessor === EMPTY_ACCESSOR ? undefined : xAccessor, - yAccessor, + yAccessors: yAccessors.split(SPLIT_Y_ACCESSORS), splitAccessor: splitAccessors[0] === EMPTY_ACCESSOR ? undefined : splitAccessors, }; }; @@ -358,6 +386,9 @@ export const getSeriesProps: GetSeriesPropsFn = ({ formattedDatatableInfo, defaultXScaleType, fieldFormats, + uiState, + allYAccessors, + singleTable, }): SeriesSpec => { const { table, isStacked, markSizeAccessor } = layer; const isPercentage = layer.isPercentage; @@ -367,7 +398,10 @@ export const getSeriesProps: GetSeriesPropsFn = ({ } const scaleType = yAxis?.scaleType || ScaleType.Linear; const isBarChart = layer.seriesType === SeriesTypes.BAR; - const xColumnId = layer.xAccessor && getAccessorByDimension(layer.xAccessor, table.columns); + const xColumnId = + layer.xAccessor !== undefined + ? getAccessorByDimension(layer.xAccessor, table.columns) + : undefined; const splitColumnIds = layer.splitAccessors?.map((splitAccessor) => { return getAccessorByDimension(splitAccessor, table.columns); @@ -377,7 +411,9 @@ export const getSeriesProps: GetSeriesPropsFn = ({ (isStacked || !splitColumnIds.length) && (isStacked || !isBarChart || !chartHasMoreThanOneBarSeries); - const formatter = table?.columns.find((column) => column.id === accessor)?.meta?.params; + const formatter = table?.columns.find( + (column) => column.id === (Array.isArray(accessor) ? accessor[0] : accessor) + )?.meta?.params; const markSizeColumnId = markSizeAccessor ? getAccessorByDimension(markSizeAccessor, table.columns) @@ -399,16 +435,22 @@ export const getSeriesProps: GetSeriesPropsFn = ({ !(xColumnId && row[xColumnId] === undefined) && !( splitColumnIds.some((splitColumnId) => row[splitColumnId] === undefined) && - row[accessor] === undefined + (Array.isArray(accessor) + ? accessor.some((a) => row[a] === undefined) + : row[accessor] === undefined) ) ); + const emptyX: Record = { + unifiedX: i18n.translate('expressionXY.xyChart.emptyXLabel', { + defaultMessage: '(empty)', + }), + }; + if (!xColumnId) { rows = rows.map((row) => ({ ...row, - unifiedX: i18n.translate('expressionXY.xyChart.emptyXLabel', { - defaultMessage: '(empty)', - }), + ...emptyX, })); } @@ -417,7 +459,7 @@ export const getSeriesProps: GetSeriesPropsFn = ({ d, { splitAccessors: layer.splitAccessors || [], - accessorsCount: layer.accessors.length, + accessorsCount: singleTable ? allYAccessors.length : layer.accessors.length, alreadyFormattedColumns: formattedColumns, columns: formattedTable.columns, splitAccessorsFormats: fieldFormats[layer.layerId].splitSeriesAccessors, @@ -429,14 +471,15 @@ export const getSeriesProps: GetSeriesPropsFn = ({ return { splitSeriesAccessors: splitColumnIds.length ? splitColumnIds : [], - stackAccessors: isStacked ? [layer.xAccessor as string] : [], + stackAccessors: isStacked && xColumnId ? [xColumnId] : [], id: generateSeriesId( layer, splitColumnIds.length ? splitColumnIds : [EMPTY_ACCESSOR], - accessor + Array.isArray(accessor) ? accessor.join(SPLIT_Y_ACCESSORS) : accessor, + xColumnId ), xAccessor: xColumnId || 'unifiedX', - yAccessors: [accessor], + yAccessors: Array.isArray(accessor) ? accessor : [accessor], markSizeAccessor: markSizeColumnId, markFormat: (value) => markFormatter.convert(value), data: rows, @@ -446,14 +489,18 @@ export const getSeriesProps: GetSeriesPropsFn = ({ ? ScaleType.LinearBinary : scaleType, color: (series) => - getColor(series, { - layer, - accessor, - colorAssignments, - paletteService, - getSeriesNameFn, - syncColors, - }), + getColor( + series, + { + layer, + colorAssignments, + paletteService, + getSeriesNameFn, + syncColors, + }, + uiState, + singleTable + ), groupId: yAxis?.groupId, enableHistogramMode, stackMode, diff --git a/src/plugins/chart_expressions/expression_xy/public/helpers/layers.ts b/src/plugins/chart_expressions/expression_xy/public/helpers/layers.ts index 359f1c27879a9b..7dc26e4c76cf1c 100644 --- a/src/plugins/chart_expressions/expression_xy/public/helpers/layers.ts +++ b/src/plugins/chart_expressions/expression_xy/public/helpers/layers.ts @@ -61,6 +61,7 @@ export interface LayerAccessorsTitles { splitSeriesTitles?: AccessorsTitles; splitColumnTitles?: AccessorsTitles; splitRowTitles?: AccessorsTitles; + markSizeTitles?: AccessorsTitles; } export type LayersAccessorsTitles = Record; @@ -80,7 +81,9 @@ export function getFilteredLayers(layers: CommonXYLayerConfig[]) { if (isDataLayer(layer)) { xAccessor = - layer.xAccessor && table && getAccessorByDimension(layer.xAccessor, table.columns); + layer.xAccessor !== undefined && table + ? getAccessorByDimension(layer.xAccessor, table.columns) + : undefined; splitAccessors = table ? layer.splitAccessors?.map((splitAccessor) => getAccessorByDimension(splitAccessor, table!.columns) @@ -190,11 +193,18 @@ const getTitleForYAccessor = ( group.series.some(({ accessor, layer }) => accessor === yAccessor && layer === layerId) ); - return axisGroup?.title || column!.name; + return column?.name ?? axisGroup?.title; }; export const getLayerTitles = ( - { xAccessor, accessors, splitAccessors = [], table, layerId }: CommonXYDataLayerConfig, + { + xAccessor, + accessors, + splitAccessors = [], + table, + layerId, + markSizeAccessor, + }: CommonXYDataLayerConfig, { splitColumnAccessor, splitRowAccessor }: SplitAccessors, { xTitle }: CustomTitles, groups: GroupsConfiguration @@ -212,8 +222,8 @@ export const getLayerTitles = ( [accessor]: getTitleForYAccessor(layerId, accessor, groups, table.columns), }); - const xColumnId = xAccessor && getAccessorByDimension(xAccessor, table.columns); - const yColumnIds = accessors.map((a) => a && getAccessorByDimension(a, table.columns)); + const xColumnId = xAccessor ? getAccessorByDimension(xAccessor, table.columns) : undefined; + const yColumnIds = accessors.map((a) => getAccessorByDimension(a, table.columns)); const splitColumnAccessors: Array = splitAccessors; return { @@ -229,6 +239,7 @@ export const getLayerTitles = ( }), {} ), + markSizeTitles: mapTitle(markSizeAccessor), splitColumnTitles: mapTitle(splitColumnAccessor), splitRowTitles: mapTitle(splitRowAccessor), }; diff --git a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap index aa2a68204108a5..37b8daab6a7a4c 100644 --- a/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_types/xy/public/__snapshots__/to_ast.test.ts.snap @@ -4,83 +4,41 @@ exports[`xy vis toExpressionAst function should match basic snapshot 1`] = ` Object { "addArgument": [Function], "arguments": Object { - "addLegend": Array [ - true, - ], "addTimeMarker": Array [ false, ], - "addTooltip": Array [ - true, - ], - "categoryAxes": Array [ + "layers": Array [ Object { "toAst": [Function], }, ], - "chartType": Array [ - "area", - ], - "gridCategoryLines": Array [ - false, - ], - "labels": Array [ + "legend": Array [ Object { "toAst": [Function], }, ], - "legendPosition": Array [ - "top", - ], - "legendSize": Array [ - "auto", - ], - "maxLegendLines": Array [ - 1, - ], - "palette": Array [ - "default", - ], - "seriesDimension": Array [ - Object { - "toAst": [Function], - }, - ], - "seriesParams": Array [ - Object { - "toAst": [Function], - }, - ], - "thresholdLine": Array [ - Object { - "toAst": [Function], - }, - ], - "times": Array [], - "truncateLegend": Array [ + "showTooltip": Array [ true, ], - "type": Array [ - "area", + "singleTable": Array [ + true, ], - "valueAxes": Array [ - Object { - "toAst": [Function], - }, + "valueLabels": Array [ + "hide", ], - "xDimension": Array [ + "xAxisConfig": Array [ Object { "toAst": [Function], }, ], - "yDimension": Array [ + "yAxisConfigs": Array [ Object { "toAst": [Function], }, ], }, "getArgument": [Function], - "name": "xy_vis", + "name": "layeredXyVis", "removeArgument": [Function], "replaceArgument": [Function], "toAst": [Function], diff --git a/src/plugins/vis_types/xy/public/to_ast.ts b/src/plugins/vis_types/xy/public/to_ast.ts index e92ca8cda82d2d..4041075b98c4d6 100644 --- a/src/plugins/vis_types/xy/public/to_ast.ts +++ b/src/plugins/vis_types/xy/public/to_ast.ts @@ -7,7 +7,8 @@ */ import moment from 'moment'; -import { Position } from '@elastic/charts'; +import { Position, ScaleType as ECScaleType } from '@elastic/charts'; +import { i18n } from '@kbn/i18n'; import { VisToExpressionAst, getVisSchemas, @@ -17,9 +18,8 @@ import { } from '@kbn/visualizations-plugin/public'; import { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/public'; import { BUCKET_TYPES } from '@kbn/data-plugin/public'; -import { Labels } from '@kbn/charts-plugin/public'; - import { TimeRangeBounds } from '@kbn/data-plugin/common'; +import { PaletteOutput } from '@kbn/charts-plugin/common/expressions/palette/types'; import { Dimensions, Dimension, @@ -29,89 +29,274 @@ import { ThresholdLine, ValueAxis, Scale, - TimeMarker, + ChartMode, + InterpolationMode, + ScaleType, } from './types'; -import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; -import { XyVisType } from '../common'; +import { ChartType } from '../common'; import { getSeriesParams } from './utils/get_series_params'; import { getSafeId } from './utils/accessors'; -const prepareLabel = (data: Labels) => { - const label = buildExpressionFunction('label', { - ...data, +interface Bounds { + min?: string | number; + max?: string | number; +} + +type YDimension = Omit & { accessor: string }; + +const getCurveType = (type?: InterpolationMode) => { + switch (type) { + case 'cardinal': + return 'CURVE_MONOTONE_X'; + case 'step-after': + return 'CURVE_STEP_AFTER'; + case 'linear': + default: + return 'LINEAR'; + } +}; + +const prepareLengend = (params: VisParams, legendSize?: LegendSize) => { + const legend = buildExpressionFunction('legendConfig', { + isVisible: params.addLegend, + maxLines: params.maxLegendLines, + position: params.legendPosition, + shouldTruncate: params.truncateLegend, + showSingleSeries: true, + legendSize, }); - return buildExpression([label]); + return buildExpression([legend]); +}; + +const getCorrectAccessor = (yAccessor: Dimension | YDimension, aggId: string) => { + return typeof yAccessor.accessor === 'number' + ? `col-${yAccessor.accessor}-${aggId}` + : yAccessor.accessor; }; -const prepareScale = (data: Scale) => { - const scale = buildExpressionFunction('visscale', { - ...data, +const prepareDecoration = (axisId: string, yAccessor: YDimension, aggId: string) => { + const dataDecorationConfig = buildExpressionFunction('dataDecorationConfig', { + forAccessor: getCorrectAccessor(yAccessor, aggId), + axisId, }); - return buildExpression([scale]); + return buildExpression([dataDecorationConfig]); }; -const prepareThresholdLine = (data: ThresholdLine) => { - const thresholdLine = buildExpressionFunction('thresholdline', { - ...data, +const preparePalette = (palette: PaletteOutput) => { + const paletteExp = buildExpressionFunction( + palette.name === 'custom' ? 'palette' : 'system_palette', + palette.name === 'custom' + ? { ...palette.params } + : { + name: palette.name, + } + ); + + return buildExpression([paletteExp]); +}; + +const prepareLayers = ( + seriesParam: SeriesParam, + isHistogram: boolean, + valueAxes: ValueAxis[], + yAccessors: YDimension[], + xAccessor: Dimension | null, + splitAccessors?: Dimension[], + markSizeAccessor?: Dimension, + palette?: PaletteOutput, + xScale?: Scale +) => { + // valueAxis.position !== Position.Left + const isHorizontal = valueAxes.some((valueAxis) => { + return ( + seriesParam.valueAxis === valueAxis.id && + valueAxis.position !== Position.Left && + valueAxis.position !== Position.Right + ); + }); + const isBar = seriesParam.type === ChartType.Histogram; + const dataLayer = buildExpressionFunction('extendedDataLayer', { + seriesType: isBar ? 'bar' : seriesParam.type, + isHistogram, + isHorizontal, + isStacked: seriesParam.mode === ChartMode.Stacked, + lineWidth: !isBar ? seriesParam.lineWidth : undefined, + showPoints: !isBar ? seriesParam.showCircles : undefined, + pointsRadius: !isBar ? seriesParam.circlesRadius ?? 3 : undefined, + showLines: !isBar ? seriesParam.drawLinesBetweenPoints : undefined, + curveType: getCurveType(seriesParam.interpolate), + decorations: yAccessors.map((accessor) => + prepareDecoration(seriesParam.valueAxis, accessor, seriesParam.data.id) + ), + accessors: yAccessors.map((accessor) => prepareVisDimension(accessor)), + xAccessor: xAccessor ? prepareVisDimension(xAccessor) : 'all', + xScaleType: getScaleType( + xScale, + xAccessor?.format?.id === 'number' || + (xAccessor?.format?.params?.id === 'number' && + xAccessor?.format?.id !== BUCKET_TYPES.RANGE && + xAccessor?.format?.id !== BUCKET_TYPES.TERMS), + 'date' in (xAccessor?.params || {}), + 'interval' in (xAccessor?.params || {}) + ), + splitAccessors: splitAccessors ? splitAccessors.map(prepareVisDimension) : undefined, + markSizeAccessor: + markSizeAccessor && !isBar ? prepareVisDimension(markSizeAccessor) : undefined, + palette: palette ? preparePalette(palette) : undefined, + columnToLabel: JSON.stringify( + [...yAccessors, xAccessor, ...(splitAccessors ?? [])].reduce>( + (acc, dimension) => { + if (dimension) { + acc[getCorrectAccessor(dimension, seriesParam.data.id)] = dimension.label; + } + + return acc; + }, + {} + ) + ), }); - return buildExpression([thresholdLine]); + return buildExpression([dataLayer]); +}; + +const getMode = (scale: Scale, bounds?: Bounds) => { + if (scale.defaultYExtents) { + return 'dataBounds'; + } + + if (scale.setYExtents || bounds) { + return 'custom'; + } +}; + +const getLabelArgs = (data: CategoryAxis, isTimeChart?: boolean) => { + return { + truncate: data.labels.truncate, + labelsOrientation: -(data.labels.rotate ?? (isTimeChart ? 0 : 90)), + showOverlappingLabels: data.labels.filter === false, + showDuplicates: data.labels.filter === false, + labelColor: data.labels.color, + showLabels: data.labels.show, + }; }; -const prepareTimeMarker = (data: TimeMarker) => { - const timeMarker = buildExpressionFunction('timemarker', { - ...data, +const prepareAxisExtentConfig = (scale: Scale, bounds?: Bounds) => { + const axisExtentConfig = buildExpressionFunction('axisExtentConfig', { + mode: getMode(scale, bounds), + lowerBound: bounds?.min || scale.min, + upperBound: bounds?.max || scale.max, + enforce: true, }); - return buildExpression([timeMarker]); + return buildExpression([axisExtentConfig]); }; -const prepareCategoryAxis = (data: CategoryAxis) => { - const categoryAxis = buildExpressionFunction('categoryaxis', { - id: data.id, - show: data.show, - position: data.position, - type: data.type, +function getScaleType( + scale?: Scale, + isNumber?: boolean, + isTime = false, + isHistogram = false +): ECScaleType | undefined { + if (isTime) return ECScaleType.Time; + if (isHistogram) return ECScaleType.Linear; + + if (!isNumber) { + return ECScaleType.Ordinal; + } + + const type = scale?.type; + if (type === ScaleType.SquareRoot) { + return ECScaleType.Sqrt; + } + + return type; +} + +function getYAxisPosition(position: Position) { + if (position === Position.Top) { + return Position.Right; + } + + if (position === Position.Bottom) { + return Position.Left; + } + + return position; +} + +function getXAxisPosition(position: Position) { + if (position === Position.Left) { + return Position.Bottom; + } + + if (position === Position.Right) { + return Position.Top; + } + + return position; +} + +const prepareXAxis = ( + data: CategoryAxis, + showGridLines?: boolean, + bounds?: Bounds, + isTimeChart?: boolean +) => { + const xAxisConfig = buildExpressionFunction('xAxisConfig', { + hide: !data.show, + position: getXAxisPosition(data.position), title: data.title.text, - scale: prepareScale(data.scale), - labels: prepareLabel(data.labels), + extent: prepareAxisExtentConfig(data.scale, bounds), + showGridLines, + ...getLabelArgs(data, isTimeChart), }); - return buildExpression([categoryAxis]); + return buildExpression([xAxisConfig]); }; -const prepareValueAxis = (data: ValueAxis) => { - const categoryAxis = buildExpressionFunction('valueaxis', { - name: data.name, - axisParams: prepareCategoryAxis({ - ...data, - }), +const prepareYAxis = (data: ValueAxis, showGridLines?: boolean) => { + const yAxisConfig = buildExpressionFunction('yAxisConfig', { + id: data.id, + hide: !data.show, + position: getYAxisPosition(data.position), + title: data.title.text, + extent: prepareAxisExtentConfig(data.scale), + boundsMargin: data.scale.boundsMargin, + scaleType: getScaleType(data.scale, true), + mode: data.scale.mode, + showGridLines, + ...getLabelArgs(data), }); - return buildExpression([categoryAxis]); + return buildExpression([yAxisConfig]); }; -const prepareSeriesParam = (data: SeriesParam) => { - const seriesParam = buildExpressionFunction('seriesparam', { - label: data.data.label, - id: data.data.id, - drawLinesBetweenPoints: data.drawLinesBetweenPoints, - interpolate: data.interpolate, - lineWidth: data.lineWidth, - mode: data.mode, - show: data.show, - showCircles: data.showCircles, - circlesRadius: data.circlesRadius, - type: data.type, - valueAxis: data.valueAxis, +const getLineStyle = (style: ThresholdLine['style']) => { + switch (style) { + case 'full': + return 'solid'; + case 'dashed': + case 'dot-dashed': + return style; + } +}; + +const prepareReferenceLine = (thresholdLine: ThresholdLine, axisId: string) => { + const referenceLine = buildExpressionFunction('referenceLine', { + value: thresholdLine.value, + color: thresholdLine.color, + lineWidth: thresholdLine.width, + lineStyle: getLineStyle(thresholdLine.style), + axisId, }); - return buildExpression([seriesParam]); + return buildExpression([referenceLine]); }; -const prepareVisDimension = (data: Dimension) => { +const prepareVisDimension = (data: Dimension | YDimension) => { const visDimension = buildExpressionFunction('visdimension', { accessor: data.accessor }); if (data.format) { @@ -122,16 +307,8 @@ const prepareVisDimension = (data: Dimension) => { return buildExpression([visDimension]); }; -const prepareXYDimension = (data: Dimension) => { - const xyDimension = buildExpressionFunction('xydimension', { - params: JSON.stringify(data.params), - aggType: data.aggType, - label: data.label, - visDimension: prepareVisDimension(data), - }); - - return buildExpression([xyDimension]); -}; +export const isDateHistogramParams = (params: Dimension['params']): params is DateHistogramParams => + (params as DateHistogramParams).date; export const toExpressionAst: VisToExpressionAst = async (vis, params) => { const schemas = getVisSchemas(vis, params); @@ -158,9 +335,12 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params const finalSeriesParams = updatedSeries ?? vis.params.seriesParams; + let isHistogram = false; + if (dimensions.x) { const xAgg = responseAggs[dimensions.x.accessor] as any; if (xAgg.type.name === BUCKET_TYPES.DATE_HISTOGRAM) { + isHistogram = true; (dimensions.x.params as DateHistogramParams).date = true; const { esUnit, esValue } = xAgg.buckets.getInterval(); (dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit; @@ -178,6 +358,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params }; } } else if (xAgg.type.name === BUCKET_TYPES.HISTOGRAM) { + isHistogram = true; const intervalParam = xAgg.type.paramByName('interval'); const output = { params: {} as any }; await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { @@ -203,47 +384,109 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } } }); + let legendSize = vis.params.legendSize; if (vis.params.legendPosition === Position.Top || vis.params.legendPosition === Position.Bottom) { legendSize = LegendSize.AUTO; } - const visTypeXy = buildExpressionFunction(visName, { - type: vis.type.name as XyVisType, - chartType: vis.params.type, - addTimeMarker: vis.params.addTimeMarker, - truncateLegend: vis.params.truncateLegend, - maxLegendLines: vis.params.maxLegendLines, - legendSize, - addLegend: vis.params.addLegend, - addTooltip: vis.params.addTooltip, - legendPosition: vis.params.legendPosition, + const yAccessors = (dimensions.y || []).reduce>( + (acc, yDimension) => { + const yAgg = responseAggs[yDimension.accessor]; + const aggId = getSafeId(yAgg.id); + const dimension: YDimension = { + ...yDimension, + accessor: getCorrectAccessor(yDimension, yAgg.id), + }; + if (acc[aggId]) { + acc[aggId].push(dimension); + } else { + acc[aggId] = [dimension]; + } + return acc; + }, + {} + ); + + const xScale = vis.params.categoryAxes[0].scale; + + let mapColumn; + + if (!dimensions.x) { + mapColumn = buildExpressionFunction('mapColumn', { + id: 'all', + expression: '_all', + name: i18n.translate('visTypeXy.allDocsTitle', { + defaultMessage: 'All docs', + }), + }); + } + + const visibleSeries = finalSeriesParams.filter( + (param) => param.show && yAccessors[param.data.id] + ); + + const visTypeXy = buildExpressionFunction('layeredXyVis', { + layers: [ + ...visibleSeries.map((seriesParams) => + prepareLayers( + seriesParams, + isHistogram, + vis.params.valueAxes, + yAccessors[seriesParams.data.id], + dimensions.x, + dimensions.series, + dimensions.z ? dimensions.z[0] : undefined, + vis.params.palette, + xScale + ) + ), + ...(vis.params.thresholdLine.show + ? [prepareReferenceLine(vis.params.thresholdLine, vis.params.valueAxes[0].id)] + : []), + ], + addTimeMarker: vis.params.addTimeMarker && (dimensions.x?.params as DateHistogramParams)?.date, orderBucketsBySum: vis.params.orderBucketsBySum, - categoryAxes: vis.params.categoryAxes.map(prepareCategoryAxis), - valueAxes: vis.params.valueAxes.map(prepareValueAxis), - seriesParams: finalSeriesParams.map(prepareSeriesParam), - labels: prepareLabel(vis.params.labels), - thresholdLine: prepareThresholdLine(vis.params.thresholdLine), - gridCategoryLines: vis.params.grid.categoryLines, - gridValueAxis: vis.params.grid.valueAxis, - radiusRatio: vis.params.radiusRatio, - isVislibVis: vis.params.isVislibVis, + fittingFunction: vis.params.fittingFunction + ? vis.params.fittingFunction.charAt(0).toUpperCase() + vis.params.fittingFunction.slice(1) + : undefined, detailedTooltip: vis.params.detailedTooltip, - 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), - widthDimension: dimensions.width?.map(prepareXYDimension), - seriesDimension: dimensions.series?.map(prepareXYDimension), - splitRowDimension: dimensions.splitRow?.map(prepareXYDimension), - splitColumnDimension: dimensions.splitColumn?.map(prepareXYDimension), + showTooltip: vis.params.addTooltip, + markSizeRatio: + dimensions.z && + visibleSeries.some((param) => param.type === ChartType.Area || param.type === ChartType.Line) + ? vis.params.radiusRatio * 0.6 // NOTE: downscale ratio to match current vislib implementation + : undefined, + legend: prepareLengend(vis.params, legendSize), + xAxisConfig: prepareXAxis( + vis.params.categoryAxes[0], + vis.params.grid.categoryLines, + dimensions.x?.params && isDateHistogramParams(dimensions.x?.params) + ? dimensions.x?.params.bounds + : undefined, + dimensions.x?.params && isDateHistogramParams(dimensions.x?.params) + ? dimensions.x?.params.date + : undefined + ), // as we have only one x axis + yAxisConfigs: vis.params.valueAxes + .filter((axis) => visibleSeries.some((seriesParam) => seriesParam.valueAxis === axis.id)) + .map((valueAxis) => prepareYAxis(valueAxis, vis.params.grid.valueAxis === valueAxis.id)), + minTimeBarInterval: + dimensions.x?.params && + isDateHistogramParams(dimensions.x?.params) && + dimensions.x?.params.date && + visibleSeries.some((param) => param.type === ChartType.Histogram) + ? dimensions.x?.params.intervalESValue + dimensions.x?.params.intervalESUnit + : undefined, + splitColumnAccessor: dimensions.splitColumn?.map(prepareVisDimension), + splitRowAccessor: dimensions.splitRow?.map(prepareVisDimension), + valueLabels: vis.params.labels.show ? 'show' : 'hide', + singleTable: true, }); - const ast = buildExpression([visTypeXy]); + const ast = buildExpression(mapColumn ? [mapColumn, visTypeXy] : [visTypeXy]); return ast.toAst(); }; diff --git a/test/functional/apps/dashboard/group1/embeddable_rendering.ts b/test/functional/apps/dashboard/group1/embeddable_rendering.ts index f57b1f1fda83ad..c0d5a47dbeb279 100644 --- a/test/functional/apps/dashboard/group1/embeddable_rendering.ts +++ b/test/functional/apps/dashboard/group1/embeddable_rendering.ts @@ -60,9 +60,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // TODO add test for 'animal sound pie' viz // This tests line charts that do not use timeseries data - const dogData = await elasticChart.getChartDebugData('visTypeXyChart', 2); - const pointCount = dogData?.areas?.reduce((acc, a) => { - return acc + a.lines.y1.points.length; + const dogData = await elasticChart.getChartDebugData('xyVisChart', 2); + const pointCount = dogData?.lines?.reduce((acc, a) => { + return acc + a.points.length; }, 0); expect(pointCount).to.equal(6); @@ -83,9 +83,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Three instead of 0 because there is a visualization based off a non time based index that // should still show data. - const dogData = await elasticChart.getChartDebugData('visTypeXyChart'); - const pointCount = dogData?.areas?.reduce((acc, a) => { - return acc + a.lines.y1.points.length; + const dogData = await elasticChart.getChartDebugData('xyVisChart', 2); + const pointCount = dogData?.lines?.reduce((acc, a) => { + return acc + a.points.length; }, 0); expect(pointCount).to.equal(6); diff --git a/test/functional/apps/dashboard/group3/dashboard_state.ts b/test/functional/apps/dashboard/group3/dashboard_state.ts index 33d5acceb00d85..8bff6355988f2e 100644 --- a/test/functional/apps/dashboard/group3/dashboard_state.ts +++ b/test/functional/apps/dashboard/group3/dashboard_state.ts @@ -31,7 +31,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const elasticChart = getService('elasticChart'); const kibanaServer = getService('kibanaServer'); const dashboardAddPanel = getService('dashboardAddPanel'); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; const enableNewChartLibraryDebug = async (force = false) => { if ((await PageObjects.visChart.isNewChartsLibraryEnabled()) || force) { diff --git a/test/functional/apps/getting_started/_shakespeare.ts b/test/functional/apps/getting_started/_shakespeare.ts index 900121f1bcf0f4..942986bdb27d69 100644 --- a/test/functional/apps/getting_started/_shakespeare.ts +++ b/test/functional/apps/getting_started/_shakespeare.ts @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'visChart', ]); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; // https://www.elastic.co/guide/en/kibana/current/tutorial-load-dataset.html diff --git a/test/functional/apps/visualize/group2/_inspector.ts b/test/functional/apps/visualize/group2/_inspector.ts index 7b306f7817f5c6..e996c2140718ef 100644 --- a/test/functional/apps/visualize/group2/_inspector.ts +++ b/test/functional/apps/visualize/group2/_inspector.ts @@ -58,7 +58,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('inspector table', function indexPatternCreation() { it('should update table header when columns change', async function () { await inspector.open(); - await inspector.expectTableHeaders(['Count']); + await inspector.expectTableHeaders(['Count', 'All docs']); await inspector.close(); log.debug('Add Average Metric on machine.ram field'); @@ -67,7 +67,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.visEditor.selectField('machine.ram', 'metrics'); await PageObjects.visEditor.clickGo(); await inspector.open(); - await inspector.expectTableHeaders(['Count', 'Average machine.ram']); + await inspector.expectTableHeaders(['Count', 'Average machine.ram', 'All docs']); await inspector.close(); }); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts index 5fbb264910dca3..309d1abb9961bc 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts @@ -26,7 +26,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'header', 'timePicker', ]); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; const vizName = 'Visualization AreaChart Name Test - Charts library'; diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts index 77ddc3bbac1a4c..4403c2157465a1 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts @@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'visChart', 'timePicker', ]); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; describe('line charts - split chart', function () { const initLineChart = async function () { @@ -116,11 +116,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show correct data, ordered by Term', async function () { const expectedChartData = [ - ['png', '1,373'], - ['php', '445'], - ['jpg', '9,109'], - ['gif', '918'], - ['css', '2,159'], + ['png', '1,373', '_all'], + ['php', '445', '_all'], + ['jpg', '9,109', '_all'], + ['gif', '918', '_all'], + ['css', '2,159', '_all'], ]; await inspector.open(); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts index a46c46fda48ad6..c1df1570008a30 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts @@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'visChart', 'timePicker', ]); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; describe('line charts - split series', function () { const initLineChart = async function () { @@ -114,11 +114,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show correct data, ordered by Term', async function () { const expectedChartData = [ - ['png', '1,373'], - ['php', '445'], - ['jpg', '9,109'], - ['gif', '918'], - ['css', '2,159'], + ['png', '1,373', '_all'], + ['php', '445', '_all'], + ['jpg', '9,109', '_all'], + ['gif', '918', '_all'], + ['css', '2,159', '_all'], ]; await inspector.open(); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts index 1a11d19064ce71..d093959f45405f 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts @@ -25,7 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'common', ]); const inspector = getService('inspector'); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; async function initChart() { log.debug('navigateToApp visualize'); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts index b8d5cd64bbc1ff..896f2ed2380677 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts @@ -18,7 +18,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const PageObjects = getPageObjects(['visualize', 'visEditor', 'visChart', 'timePicker']); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; describe('vertical bar chart', function () { before(async () => { diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts index 4f00bac7792c40..7d8ffe17566fea 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts @@ -16,7 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const inspector = getService('inspector'); const PageObjects = getPageObjects(['common', 'visualize', 'header', 'visEditor', 'visChart']); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; describe('vertical bar chart with index without time filter', function () { const vizName1 = 'Visualization VerticalBarChart without time filter'; diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts index 1caae58ad5af65..5521762f865e67 100644 --- a/test/functional/page_objects/visualize_chart_page.ts +++ b/test/functional/page_objects/visualize_chart_page.ts @@ -135,9 +135,7 @@ export class VisualizeChartPageObject extends FtrService { * @param axis axis value, 'ValueAxis-1' by default */ public async getLineChartData(selector: string, dataLabel = 'Count') { - // For now lines are rendered as areas to enable stacking - const areas = (await this.getEsChartDebugState(selector))?.areas ?? []; - const lines = areas.map(({ lines: { y1 }, name, color }) => ({ ...y1, name, color })); + const lines = (await this.getEsChartDebugState(selector))?.lines ?? []; const points = lines.find(({ name }) => name === dataLabel)?.points ?? []; return points.map(({ y }) => y); } diff --git a/test/functional/screenshots/baseline/area_chart.png b/test/functional/screenshots/baseline/area_chart.png index 7bbaa256f036098b8b8256e4a39e111024b65a42..7a0d5be0477127810f7a6334b3fd78a8202d6b6b 100644 GIT binary patch literal 190569 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 z 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

    V>&!E(b0i)#P+!`Y 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�SrmkHV9x%DTnE-k!Z-}#HYI40bL!Xc|b8_={zqlgsLR@%tPfgjzOCgeX%W%v@8d zU;SfLi4IN+dqUd9Al3HMcN1RT&C~o?l!VBvvnGS2Z>fV@AFHMj0@3`gEI#$=6iLk< zOJxsB?JygfQm_MR|2*;j4vs_5_`MU<^%=pSc@5p<@Dv8*wP6$H#&|Ji8|T*^vx(g< z=!{t0RK3N;8Nd9lfd9Cf;V z9Z?mKHe{P>aWj-G;iK4)lYOr%8n0t2l+5Kd#zla9-Yi;OyN7u;syM4jeAvKQw=Y{EDHgH6J16Pn zUVHv$q+WG<8( zdgVLFeHCtubOnd|aw1u0y$Ln@-D80Vvn`<$^jlg4KhT#3*wE(0OO$1YN zRm5zW16Tf?4vWjszxejzqL*LktEq9}Q;T6h;<*lWJ-qUUFFm~8zwH>c!1&?W@Q{QA zH%-uo8y^CcXRc2nme{oh_>7G5c;ux1+p|KFd729)TlLJdRnHF7qLP9O3n_muIenqo z=WKwB&_#6(G8YO`Z0~Ywdh~uo+UN zHV@8t$HBdAHBx$R?oGtS1!k7@%t4Vd)K_bxvZCUlc(if4R`%9FUyr=CwUCt5M^5{G zmx{1K-=A+(^z$MFQTpp*`XooN!{e_`y-I8)(M@pmynym@o}hbc!Dq$nrRC+)?~-Cy zr(|7CS6&t#B%@=S7l}&)XNS6}7%lRG5xM@2{$+>w;m={3&YPZ=;J%Rh5@jPO~=MjZkZSwU_}# zct?TFc>|llBBpCSod0k}dfmQ+uA#)VuFgAcM7!7(V`Ii9uOB)VW24{9H+50xV>~jt zcr~%B0r4vy+8W}m6Me@`_Qy%^@pOeuT>lnC^MajJg9>VISU>*s@w8el=Bk}t@#+{o zIejp}Z~`LVn=EeJrd7p zS2MILJ8C6zknQBilE&a)p-BV2@ItZfPOU*W_>s*1=GNw5roP3H`>>nX)r0wX(GR0#%S$A4>I+)Y(a{U- zd9TY68e>gyg5BNSgFj(U&W_f;M>*v>zJY*?3keMg)D&Khc6@b>^gySOS(-@c@j)D1 z^B6rjHm}XI>eSNOkJo0EEmA!bJ;|Wp98Z?`wK$>~86u(@pvpfj7C~hL;X_itATead z`+Kkk@EVe>{&`{#w^uz->ILkPmXB27v%0ADto`oFEX8W5;$_^!xOANe%P&--niel} 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

    A-A;AR&`jrF( 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 @@ -429,7 +430,8 @@ const dataLayerToExpression = ( datasourceLayer: DatasourcePublicAPI | undefined, metadata: Record>, paletteService: PaletteRegistry, - datasourceExpression: Ast + datasourceExpression: Ast, + curveType: XYCurveType ): Ast => { const columnToLabel = getColumnToLabelMap(layer, datasourceLayer); @@ -451,6 +453,24 @@ const dataLayerToExpression = ( return { type: 'expression', chain: [ + ...(datasourceExpression + ? [ + ...datasourceExpression.chain, + ...(layer.collapseFn + ? [ + { + type: 'function', + function: 'lens_collapse', + arguments: { + by: layer.xAccessor ? [layer.xAccessor] : [], + metric: layer.accessors, + fn: [layer.collapseFn!], + }, + } as AstFunction, + ] + : []), + ] + : []), { type: 'function', function: 'extendedDataLayer', @@ -469,35 +489,11 @@ const dataLayerToExpression = ( yConfigToDataDecorationConfigExpression(yConfig, yAxisConfigs) ) : [], + curveType: [curveType], seriesType: [seriesType], showLines: seriesType === 'line' || seriesType === 'area' ? [true] : [false], accessors: layer.accessors, columnToLabel: [JSON.stringify(columnToLabel)], - ...(datasourceExpression - ? { - table: [ - { - ...datasourceExpression, - chain: [ - ...datasourceExpression.chain, - ...(layer.collapseFn - ? [ - { - type: 'function', - function: 'lens_collapse', - arguments: { - by: layer.xAccessor ? [layer.xAccessor] : [], - metric: layer.accessors, - fn: [layer.collapseFn!], - }, - } as AstFunction, - ] - : []), - ], - }, - ], - } - : {}), palette: [ { type: 'expression', diff --git a/x-pack/test/functional/fixtures/kbn_archiver/dashboard_async/async_search.json b/x-pack/test/functional/fixtures/kbn_archiver/dashboard_async/async_search.json index 8dbd2dedeaf720..08a64e34168f1f 100644 --- a/x-pack/test/functional/fixtures/kbn_archiver/dashboard_async/async_search.json +++ b/x-pack/test/functional/fixtures/kbn_archiver/dashboard_async/async_search.json @@ -50,7 +50,7 @@ "title": "Sum of Bytes by Extension (Delayed 5s)", "uiStateJSON": "{}", "version": 1, - "visState": "{\"title\":\"Sum of Bytes by Extension (Delayed 5s)\",\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"params\":{\"field\":\"bytes\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"extension.raw\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"shard_delay\",\"params\":{\"delay\":\"5s\"},\"schema\":\"group\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":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 bytes\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Sum of bytes\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"circlesRadius\":1}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"row\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"legendSize\":\"auto\"}}" + "visState": "{\"title\":\"Sum of Bytes by Extension (Delayed 5s)\",\"type\":\"histogram\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"sum\",\"params\":{\"field\":\"bytes\"},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"extension.raw\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"},\"schema\":\"segment\"},{\"id\":\"3\",\"enabled\":true,\"type\":\"shard_delay\",\"params\":{\"delay\":\"5s\"},\"schema\":\"split\"}],\"params\":{\"type\":\"histogram\",\"grid\":{\"categoryLines\":false},\"categoryAxes\":[{\"id\":\"CategoryAxis-1\",\"type\":\"category\",\"position\":\"bottom\",\"show\":true,\"style\":{},\"scale\":{\"type\":\"linear\"},\"labels\":{\"show\":true,\"filter\":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 bytes\"}}],\"seriesParams\":[{\"show\":true,\"type\":\"histogram\",\"mode\":\"stacked\",\"data\":{\"label\":\"Sum of bytes\",\"id\":\"1\"},\"valueAxis\":\"ValueAxis-1\",\"drawLinesBetweenPoints\":true,\"lineWidth\":2,\"showCircles\":true,\"circlesRadius\":1}],\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"times\":[],\"addTimeMarker\":false,\"labels\":{\"show\":false},\"thresholdLine\":{\"show\":false,\"value\":10,\"width\":1,\"style\":\"full\",\"color\":\"#E7664C\"},\"row\":true,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"isVislibVis\":true,\"detailedTooltip\":true,\"legendSize\":\"auto\"}}" }, "coreMigrationVersion": "8.4.0", "id": "6c9f3830-01e3-11eb-9b63-176d7b28a352", diff --git a/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/async_search.ts b/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/async_search.ts index 95f2a1f926ad79..d37d8a937601aa 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/async_search.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/async_search.ts @@ -16,7 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dashboardPanelActions = getService('dashboardPanelActions'); const queryBar = getService('queryBar'); const elasticChart = getService('elasticChart'); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; const enableNewChartLibraryDebug = async () => { await elasticChart.setNewChartUiDebugFlag(); diff --git a/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/save_search_session.ts b/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/save_search_session.ts index 41ecf3b3015d4c..ded0f097abdc7f 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/save_search_session.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/dashboard/async_search/save_search_session.ts @@ -104,7 +104,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.switchToEditMode(); await searchSessions.expectState('restored'); - const xyChartSelector = 'visTypeXyChart'; + const xyChartSelector = 'xyVisChart'; await enableNewChartLibraryDebug(); const data = await PageObjects.visChart.getBarChartData(xyChartSelector, 'Sum of bytes'); expect(data.length).to.be(5); From 3aabd88c16e90a5c736c6351271a29581f546482 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 11 Aug 2022 17:48:38 +0200 Subject: [PATCH 23/59] [ML] APM Correlations: Fix chart errors caused by inconsistent histogram range steps. (#138259) The `AreaSeries` for the latency correlations charts expect the provided timestamp keys for each series to be the same, otherwise there might be errors in how the chart renders the areas. In some cases this could happen because we fetch the data for the areas independently (for example overall latency and failed transactions latency). The fix provided by this PR adds optional `durationMin` and `durationMax` parameters to affected endpoints. This way the `durationMin/Max` returned by the first area request (for example "overall latency") can be passed on to the second request to enforce the same buckets/keys (for example for "failed transaction latency"). --- ..._failed_transactions_correlations.test.tsx | 41 ++++-- .../use_failed_transactions_correlations.ts | 117 +++++++++++------- .../correlations/use_latency_correlations.ts | 38 +++--- ...use_transaction_distribution_chart_data.ts | 8 +- .../index.test.tsx | 10 +- .../duration_distribution_chart/index.tsx | 63 ++++++---- .../fetch_duration_histogram_range_steps.ts | 39 ++++-- .../correlations/queries/fetch_p_values.ts | 8 +- .../queries/fetch_significant_correlations.ts | 12 +- .../apm/server/routes/correlations/route.ts | 12 ++ .../get_overall_latency_distribution.ts | 30 +++-- .../routes/latency_distribution/route.ts | 6 + .../routes/latency_distribution/types.ts | 2 + 13 files changed, 265 insertions(+), 121 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx index 76eea019ac83e0..54d455519329c7 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx +++ b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx @@ -168,11 +168,12 @@ describe('useFailedTransactionsCorrelations', () => { ); try { + // Each simulated request takes 100ms. After an inital 50ms + // we track the internal requests the hook is running and + // check the expected progress after these requests. jest.advanceTimersByTime(50); await waitFor(() => expect(result.current.progress.loaded).toBe(0)); jest.advanceTimersByTime(100); - await waitFor(() => expect(result.current.progress.loaded).toBe(0)); - jest.advanceTimersByTime(100); await waitFor(() => expect(result.current.progress.loaded).toBe(0.05)); expect(result.current.progress).toEqual({ @@ -180,6 +181,28 @@ describe('useFailedTransactionsCorrelations', () => { isRunning: true, loaded: 0.05, }); + expect(result.current.response).toEqual({ + ccsWarning: false, + fieldStats: undefined, + errorHistogram: undefined, + failedTransactionsCorrelations: undefined, + overallHistogram: [ + { + doc_count: 1234, + key: 'the-key', + }, + ], + percentileThresholdValue: 1.234, + }); + + jest.advanceTimersByTime(100); + await waitFor(() => expect(result.current.progress.loaded).toBe(0.1)); + + expect(result.current.progress).toEqual({ + error: undefined, + isRunning: true, + loaded: 0.1, + }); expect(result.current.response).toEqual({ ccsWarning: false, fieldStats: undefined, @@ -200,23 +223,23 @@ describe('useFailedTransactionsCorrelations', () => { }); jest.advanceTimersByTime(100); - await waitFor(() => expect(result.current.progress.loaded).toBe(0.1)); + await waitFor(() => expect(result.current.progress.loaded).toBe(0.15)); // field candidates are an implementation detail and - // will not be exposed, it will just set loaded to 0.1. + // will not be exposed, it will just set loaded to 0.15. expect(result.current.progress).toEqual({ error: undefined, isRunning: true, - loaded: 0.1, + loaded: 0.15, }); jest.advanceTimersByTime(100); - await waitFor(() => expect(result.current.progress.loaded).toBe(1)); + await waitFor(() => expect(result.current.progress.loaded).toBe(0.9)); expect(result.current.progress).toEqual({ error: undefined, isRunning: true, - loaded: 1, + loaded: 0.9, }); expect(result.current.response).toEqual({ @@ -252,9 +275,7 @@ describe('useFailedTransactionsCorrelations', () => { }); jest.advanceTimersByTime(100); - await waitFor(() => - expect(result.current.response.fieldStats).toBeDefined() - ); + await waitFor(() => expect(result.current.progress.loaded).toBe(1)); expect(result.current.progress).toEqual({ error: undefined, diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.ts b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.ts index 4119d9e2e4daef..f9c365c539e0f9 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.ts +++ b/x-pack/plugins/apm/public/components/app/correlations/use_failed_transactions_correlations.ts @@ -37,9 +37,10 @@ import { useFetchParams } from './use_fetch_params'; // Overall progress is a float from 0 to 1. const LOADED_OVERALL_HISTOGRAM = 0.05; -const LOADED_FIELD_CANDIDATES = LOADED_OVERALL_HISTOGRAM + 0.05; +const LOADED_ERROR_HISTOGRAM = LOADED_OVERALL_HISTOGRAM + 0.05; +const LOADED_FIELD_CANDIDATES = LOADED_ERROR_HISTOGRAM + 0.05; const LOADED_DONE = 1; -const PROGRESS_STEP_P_VALUES = 0.9; +const PROGRESS_STEP_P_VALUES = 0.9 - LOADED_FIELD_CANDIDATES; export function useFailedTransactionsCorrelations() { const fetchParams = useFetchParams(); @@ -85,61 +86,78 @@ export function useFailedTransactionsCorrelations() { fallbackResult: undefined, }; - const [overallHistogramResponse, errorHistogramRespone] = - await Promise.all([ - // Initial call to fetch the overall distribution for the log-log plot. - callApmApi( - 'POST /internal/apm/latency/overall_distribution/transactions', - { - signal: abortCtrl.current.signal, - params: { - body: { - ...fetchParams, - percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, - chartType: - LatencyDistributionChartType.failedTransactionsCorrelations, - }, - }, - } - ), - callApmApi( - 'POST /internal/apm/latency/overall_distribution/transactions', - { - signal: abortCtrl.current.signal, - params: { - body: { - ...fetchParams, - percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, - termFilters: [ - { - fieldName: EVENT_OUTCOME, - fieldValue: EventOutcome.failure, - }, - ], - chartType: - LatencyDistributionChartType.failedTransactionsCorrelations, - }, - }, - } - ), - ]); + // Initial call to fetch the overall distribution for the log-log plot. + const overallHistogramResponse = await callApmApi( + 'POST /internal/apm/latency/overall_distribution/transactions', + { + signal: abortCtrl.current.signal, + params: { + body: { + ...fetchParams, + percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, + chartType: + LatencyDistributionChartType.failedTransactionsCorrelations, + }, + }, + } + ); + + if (abortCtrl.current.signal.aborted) { + return; + } - const { overallHistogram, totalDocCount, percentileThresholdValue } = - overallHistogramResponse; - const { overallHistogram: errorHistogram } = errorHistogramRespone; + const { + overallHistogram, + totalDocCount, + percentileThresholdValue, + durationMin, + durationMax, + } = overallHistogramResponse; - responseUpdate.errorHistogram = errorHistogram; responseUpdate.overallHistogram = overallHistogram; responseUpdate.totalDocCount = totalDocCount; responseUpdate.percentileThresholdValue = percentileThresholdValue; + setResponse({ + ...responseUpdate, + loaded: LOADED_OVERALL_HISTOGRAM, + }); + setResponse.flush(); + + const errorHistogramResponse = await callApmApi( + 'POST /internal/apm/latency/overall_distribution/transactions', + { + signal: abortCtrl.current.signal, + params: { + body: { + ...fetchParams, + percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, + termFilters: [ + { + fieldName: EVENT_OUTCOME, + fieldValue: EventOutcome.failure, + }, + ], + durationMin, + durationMax, + chartType: + LatencyDistributionChartType.failedTransactionsCorrelations, + }, + }, + } + ); + if (abortCtrl.current.signal.aborted) { return; } + const { overallHistogram: errorHistogram } = errorHistogramResponse; + + responseUpdate.errorHistogram = errorHistogram; + setResponse({ ...responseUpdate, - loaded: LOADED_OVERALL_HISTOGRAM, + loaded: LOADED_ERROR_HISTOGRAM, }); setResponse.flush(); @@ -179,7 +197,12 @@ export function useFailedTransactionsCorrelations() { { signal: abortCtrl.current.signal, params: { - body: { ...fetchParams, fieldCandidates: fieldCandidatesChunk }, + body: { + ...fetchParams, + fieldCandidates: fieldCandidatesChunk, + durationMin, + durationMax, + }, }, } ); @@ -284,7 +307,7 @@ export function useFailedTransactionsCorrelations() { const progress = useMemo( () => ({ error, - loaded, + loaded: Math.round(loaded * 100) / 100, isRunning, }), [error, loaded, isRunning] diff --git a/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.ts b/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.ts index b46aaf815d6ade..b2ba6fc4c68b15 100644 --- a/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.ts +++ b/x-pack/plugins/apm/public/components/app/correlations/use_latency_correlations.ts @@ -86,20 +86,25 @@ export function useLatencyCorrelations() { }; // Initial call to fetch the overall distribution for the log-log plot. - const { overallHistogram, totalDocCount, percentileThresholdValue } = - await callApmApi( - 'POST /internal/apm/latency/overall_distribution/transactions', - { - signal: abortCtrl.current.signal, - params: { - body: { - ...fetchParams, - percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, - chartType: LatencyDistributionChartType.latencyCorrelations, - }, + const { + overallHistogram, + totalDocCount, + percentileThresholdValue, + durationMin, + durationMax, + } = await callApmApi( + 'POST /internal/apm/latency/overall_distribution/transactions', + { + signal: abortCtrl.current.signal, + params: { + body: { + ...fetchParams, + percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, + chartType: LatencyDistributionChartType.latencyCorrelations, }, - } - ); + }, + } + ); responseUpdate.overallHistogram = overallHistogram; responseUpdate.totalDocCount = totalDocCount; responseUpdate.percentileThresholdValue = percentileThresholdValue; @@ -192,7 +197,12 @@ export function useLatencyCorrelations() { { signal: abortCtrl.current.signal, params: { - body: { ...fetchParams, fieldValuePairs: fieldValuePairChunk }, + body: { + ...fetchParams, + durationMin, + durationMax, + fieldValuePairs: fieldValuePairChunk, + }, }, } ); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/use_transaction_distribution_chart_data.ts b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/use_transaction_distribution_chart_data.ts index 42febda7a186fb..77f284e0ffee7f 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/use_transaction_distribution_chart_data.ts +++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/use_transaction_distribution_chart_data.ts @@ -86,7 +86,9 @@ export const useTransactionDistributionChartData = () => { params.serviceName && params.environment && params.start && - params.end + params.end && + overallLatencyData.durationMin && + overallLatencyData.durationMax ) { return callApmApi( 'POST /internal/apm/latency/overall_distribution/transactions', @@ -94,6 +96,8 @@ export const useTransactionDistributionChartData = () => { params: { body: { ...params, + durationMin: overallLatencyData.durationMin, + durationMax: overallLatencyData.durationMax, percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD, termFilters: [ { @@ -108,7 +112,7 @@ export const useTransactionDistributionChartData = () => { ); } }, - [params] + [params, overallLatencyData.durationMin, overallLatencyData.durationMax] ); useEffect(() => { diff --git a/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.test.tsx index 6af1c89fd1991c..05cedbdc1e3917 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.test.tsx @@ -7,11 +7,11 @@ import type { HistogramItem } from '../../../../../common/correlations/types'; -import { replaceHistogramDotsWithBars } from '.'; +import { replaceHistogramZerosWithMinimumDomainValue } from '.'; describe('TransactionDistributionChart', () => { - describe('replaceHistogramDotsWithBars', () => { - it('does the thing', () => { + describe('replaceHistogramZerosWithMinimumDomainValue', () => { + it('replaces zeroes', () => { const mockHistogram = [ { doc_count: 10 }, { doc_count: 10 }, @@ -25,7 +25,9 @@ describe('TransactionDistributionChart', () => { { doc_count: 10 }, ] as HistogramItem[]; - expect(replaceHistogramDotsWithBars(mockHistogram)).toEqual([ + expect( + replaceHistogramZerosWithMinimumDomainValue(mockHistogram) + ).toEqual([ { doc_count: 10 }, { doc_count: 10 }, { doc_count: 0.0001 }, diff --git a/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.tsx index 8e688832f7f36c..49885977b57dd7 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/duration_distribution_chart/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { flatten } from 'lodash'; import { @@ -83,18 +83,21 @@ const getAnnotationsStyle = (color = 'gray'): LineAnnotationStyle => ({ }, }); -// TODO Revisit this approach since it actually manipulates the numbers -// showing in the chart and its tooltips. -const CHART_PLACEHOLDER_VALUE = 0.0001; +// With a log based y axis in combination with the `CURVE_STEP_AFTER` style, +// the line of an area would not go down to 0 but end on the y axis at the last value >0. +// By replacing the 0s with a small value >0 the line will be drawn as intended. +// This is just to visually fix the line, for tooltips, that number will be again rounded down to 0. +// Note this workaround is only safe to use for this type of chart because it works with +// count based values and not a float based metric for example on the y axis. +const Y_AXIS_MIN_DOMAIN = 0.5; +const Y_AXIS_MIN_VALUE = 0.0001; -// Elastic charts will show any lone bin (i.e. a populated bin followed by empty bin) -// as a circular marker instead of a bar -// This provides a workaround by making the next bin not empty -// TODO Find a way to get rid of this workaround since it alters original values of the data. -export const replaceHistogramDotsWithBars = (histogramItems: HistogramItem[]) => +export const replaceHistogramZerosWithMinimumDomainValue = ( + histogramItems: HistogramItem[] +) => histogramItems.reduce((histogramItem, _, i) => { if (histogramItem[i].doc_count === 0) { - histogramItem[i].doc_count = CHART_PLACEHOLDER_VALUE; + histogramItem[i].doc_count = Y_AXIS_MIN_VALUE; } return histogramItem; }, histogramItems); @@ -140,9 +143,10 @@ export function DurationDistributionChart({ ...flatten(data.map((d) => d.histogram)).map((d) => d.doc_count) ) ?? 0; const yTicks = Math.max(1, Math.ceil(Math.log10(yMax))); + const yAxisMaxDomain = Math.pow(10, yTicks); const yAxisDomain = { - min: 0.5, - max: Math.pow(10, yTicks), + min: Y_AXIS_MIN_DOMAIN, + max: yAxisMaxDomain, }; const selectionAnnotation = @@ -153,13 +157,22 @@ export function DurationDistributionChart({ x0: selection[0], x1: selection[1], y0: 0, - y1: 100000, + y1: yAxisMaxDomain, }, details: 'selection', }, ] : undefined; + const chartData = useMemo( + () => + data.map((d) => ({ + ...d, + histogram: replaceHistogramZerosWithMinimumDomainValue(d.histogram), + })), + [data] + ); + return (
    - {data.map((d, i) => ( + {chartData.map((d) => ( `${Math.round(p)}`} + tickFormat={(p) => `${Math.floor(p)}`} /> ))} diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts index 913bec60d9de8c..f1ba0347f7fcce 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_duration_histogram_range_steps.ts @@ -32,14 +32,35 @@ export const fetchDurationHistogramRangeSteps = async ({ kuery, query, searchMetrics, + durationMinOverride, + durationMaxOverride, }: CommonCorrelationsQueryParams & { chartType: LatencyDistributionChartType; setup: Setup; searchMetrics: boolean; -}): Promise => { + durationMinOverride?: number; + durationMaxOverride?: number; +}): Promise<{ + durationMin?: number; + durationMax?: number; + rangeSteps: number[]; +}> => { + const steps = 100; + + if (durationMinOverride && durationMaxOverride) { + return { + durationMin: durationMinOverride, + durationMax: durationMaxOverride, + rangeSteps: getHistogramRangeSteps( + durationMinOverride, + durationMaxOverride, + steps + ), + }; + } + const { apmEventClient } = setup; - const steps = 100; const durationField = getDurationField(chartType, searchMetrics); // when using metrics data, ensure we filter by docs with the appropriate duration field @@ -71,7 +92,7 @@ export const fetchDurationHistogramRangeSteps = async ({ ); if (resp.hits.total.value === 0) { - return getHistogramRangeSteps(0, 1, 100); + return { rangeSteps: getHistogramRangeSteps(0, 1, 100) }; } if ( @@ -81,11 +102,15 @@ export const fetchDurationHistogramRangeSteps = async ({ isFiniteNumber(resp.aggregations.duration_max.value) ) ) { - return []; + return { rangeSteps: [] }; } - const min = resp.aggregations.duration_min.value; - const max = resp.aggregations.duration_max.value * 2; + const durationMin = resp.aggregations.duration_min.value; + const durationMax = resp.aggregations.duration_max.value * 2; - return getHistogramRangeSteps(min, max, steps); + return { + durationMin, + durationMax, + rangeSteps: getHistogramRangeSteps(durationMin, durationMax, steps), + }; }; diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts index f52c9bcfa51c6d..72cd6baaefec43 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_p_values.ts @@ -22,16 +22,20 @@ export const fetchPValues = async ({ environment, kuery, query, + durationMin, + durationMax, fieldCandidates, }: CommonCorrelationsQueryParams & { setup: Setup; + durationMin?: number; + durationMax?: number; fieldCandidates: string[]; }) => { const chartType = LatencyDistributionChartType.failedTransactionsCorrelations; const searchMetrics = false; // failed transactions correlations does not search metrics documents const eventType = getEventType(chartType, searchMetrics); - const rangeSteps = await fetchDurationHistogramRangeSteps({ + const { rangeSteps } = await fetchDurationHistogramRangeSteps({ setup, chartType, start, @@ -40,6 +44,8 @@ export const fetchPValues = async ({ kuery, query, searchMetrics, + durationMinOverride: durationMin, + durationMaxOverride: durationMax, }); const { fulfilled, rejected } = splitAllSettledPromises( diff --git a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts index 9799f75d82241d..abb23fbfac0e8e 100644 --- a/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts +++ b/x-pack/plugins/apm/server/routes/correlations/queries/fetch_significant_correlations.ts @@ -34,9 +34,13 @@ export const fetchSignificantCorrelations = async ({ environment, kuery, query, + durationMinOverride, + durationMaxOverride, fieldValuePairs, }: CommonCorrelationsQueryParams & { setup: Setup; + durationMinOverride?: number; + durationMaxOverride?: number; fieldValuePairs: FieldValuePair[]; }) => { // Create an array of ranges [2, 4, 6, ..., 98] @@ -75,7 +79,7 @@ export const fetchSignificantCorrelations = async ({ ranges, }); - const histogramRangeSteps = await fetchDurationHistogramRangeSteps({ + const { rangeSteps } = await fetchDurationHistogramRangeSteps({ setup, chartType, start, @@ -84,6 +88,8 @@ export const fetchSignificantCorrelations = async ({ kuery, query, searchMetrics, + durationMinOverride, + durationMaxOverride, }); const { fulfilled, rejected } = splitAllSettledPromises( @@ -100,7 +106,7 @@ export const fetchSignificantCorrelations = async ({ expectations, ranges, fractions, - histogramRangeSteps, + histogramRangeSteps: rangeSteps, totalDocCount, fieldValuePair, }) @@ -147,7 +153,7 @@ export const fetchSignificantCorrelations = async ({ filter: [query, ...termQuery(fieldName, fieldValue)], }, }, - rangeSteps: histogramRangeSteps, + rangeSteps, searchMetrics, }); diff --git a/x-pack/plugins/apm/server/routes/correlations/route.ts b/x-pack/plugins/apm/server/routes/correlations/route.ts index 4000dcb53676ef..fd3a405bc7a953 100644 --- a/x-pack/plugins/apm/server/routes/correlations/route.ts +++ b/x-pack/plugins/apm/server/routes/correlations/route.ts @@ -307,6 +307,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({ serviceName: t.string, transactionName: t.string, transactionType: t.string, + durationMin: toNumberRt, + durationMax: toNumberRt, }), environmentRt, kueryRt, @@ -343,6 +345,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({ end, environment, kuery, + durationMin, + durationMax, fieldValuePairs, }, } = resources.params; @@ -362,6 +366,8 @@ const significantCorrelationsTransactionsRoute = createApmServerRoute({ ], }, }, + durationMinOverride: durationMin, + durationMaxOverride: durationMax, fieldValuePairs, }); }, @@ -375,6 +381,8 @@ const pValuesTransactionsRoute = createApmServerRoute({ serviceName: t.string, transactionName: t.string, transactionType: t.string, + durationMin: toNumberRt, + durationMax: toNumberRt, }), environmentRt, kueryRt, @@ -405,6 +413,8 @@ const pValuesTransactionsRoute = createApmServerRoute({ end, environment, kuery, + durationMin, + durationMax, fieldCandidates, }, } = resources.params; @@ -424,6 +434,8 @@ const pValuesTransactionsRoute = createApmServerRoute({ ], }, }, + durationMin, + durationMax, fieldCandidates, }); }, diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts b/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts index b44c071f2ab376..206deb8a32d15d 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/get_overall_latency_distribution.ts @@ -28,6 +28,8 @@ export async function getOverallLatencyDistribution({ kuery, query, percentileThreshold, + durationMinOverride, + durationMaxOverride, searchMetrics, }: { chartType: LatencyDistributionChartType; @@ -38,6 +40,8 @@ export async function getOverallLatencyDistribution({ kuery: string; query: estypes.QueryDslQueryContainer; percentileThreshold: number; + durationMinOverride?: number; + durationMaxOverride?: number; searchMetrics: boolean; }) { return withApmSpan('get_overall_latency_distribution', async () => { @@ -63,23 +67,25 @@ export async function getOverallLatencyDistribution({ } // #2: get histogram range steps - const rangeSteps = await fetchDurationHistogramRangeSteps({ - chartType, - setup, - start, - end, - environment, - kuery, - query, - searchMetrics, - }); + const { durationMin, durationMax, rangeSteps } = + await fetchDurationHistogramRangeSteps({ + chartType, + setup, + start, + end, + environment, + kuery, + query, + searchMetrics, + durationMinOverride, + durationMaxOverride, + }); if (!rangeSteps) { return overallLatencyDistribution; } // #3: get histogram chart data - const { totalDocCount, durationRanges } = await fetchDurationRanges({ chartType, setup, @@ -92,6 +98,8 @@ export async function getOverallLatencyDistribution({ searchMetrics, }); + overallLatencyDistribution.durationMin = durationMin; + overallLatencyDistribution.durationMax = durationMax; overallLatencyDistribution.totalDocCount = totalDocCount; overallLatencyDistribution.overallHistogram = durationRanges; diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts index 5fc2072bad2248..7eaaa6e641030c 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts @@ -38,6 +38,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ fieldValue: t.union([t.string, toNumberRt]), }) ), + durationMin: toNumberRt, + durationMax: toNumberRt, }), environmentRt, kueryRt, @@ -63,6 +65,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ start, end, percentileThreshold, + durationMin, + durationMax, termFilters, chartType, } = resources.params.body; @@ -99,6 +103,8 @@ const latencyOverallTransactionDistributionRoute = createApmServerRoute({ }, }, percentileThreshold, + durationMinOverride: durationMin, + durationMaxOverride: durationMax, searchMetrics: searchAggregatedTransactions, }); }, diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/types.ts b/x-pack/plugins/apm/server/routes/latency_distribution/types.ts index 92129f1a5f2348..4fb19eba4e57d6 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/types.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/types.ts @@ -18,6 +18,8 @@ export interface OverallLatencyDistributionOptions { } export interface OverallLatencyDistributionResponse { + durationMin?: number; + durationMax?: number; totalDocCount?: number; percentileThresholdValue?: number | null; overallHistogram?: Array<{ From 01f8c7c4f2df0ddbcc9d0be2fe34eceb4d5dd059 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Thu, 11 Aug 2022 09:11:42 -0700 Subject: [PATCH 24/59] [DOCS] Add missing collapsible sections in case APIs (#138588) --- docs/api/cases/cases-api-add-comment.asciidoc | 1 + docs/api/cases/cases-api-create.asciidoc | 14 ++++++++------ .../api/cases/cases-api-set-configuration.asciidoc | 1 + docs/api/cases/cases-api-update-comment.asciidoc | 1 + .../cases/cases-api-update-configuration.asciidoc | 1 + docs/api/cases/cases-api-update.asciidoc | 14 ++++++++------ 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/api/cases/cases-api-add-comment.asciidoc b/docs/api/cases/cases-api-add-comment.asciidoc index 69f886e3a5c9a3..618f4a5de88425 100644 --- a/docs/api/cases/cases-api-add-comment.asciidoc +++ b/docs/api/cases/cases-api-add-comment.asciidoc @@ -29,6 +29,7 @@ You must have `all` privileges for the *Cases* feature in the *Management*, (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === {api-request-body-title} `alertId`:: diff --git a/docs/api/cases/cases-api-create.asciidoc b/docs/api/cases/cases-api-create.asciidoc index 402521a4c31e77..b499e8436aa548 100644 --- a/docs/api/cases/cases-api-create.asciidoc +++ b/docs/api/cases/cases-api-create.asciidoc @@ -25,6 +25,7 @@ You must have `all` privileges for the *Cases* feature in the *Management*, (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === {api-request-body-title} `connector`:: @@ -34,12 +35,13 @@ default space is used. [%collapsible%open] ==== `fields`:: -(Required, object) An object containing the connector fields. +(Required, object) An object containing the connector fields. To create a case +without a connector, specify `null`. If you want to omit any individual field, +specify `null` as its value. + --- -To create a case without a connector, specify `null`. If you want to omit any -individual field, specify `null` as its value. - +.Properties of `fields` +[%collapsible%open] +===== For {ibm-r} connectors, specify: `issueTypes`::: @@ -103,7 +105,7 @@ For {swimlane} connectors, specify: `caseId`::: (Required, string) The case ID. --- +===== `id`:: (Required, string) The identifier for the connector. To create a case without a diff --git a/docs/api/cases/cases-api-set-configuration.asciidoc b/docs/api/cases/cases-api-set-configuration.asciidoc index 89ec6f0600717a..2deaaf7fdff090 100644 --- a/docs/api/cases/cases-api-set-configuration.asciidoc +++ b/docs/api/cases/cases-api-set-configuration.asciidoc @@ -35,6 +35,7 @@ you must still specify all of the connector details. (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === {api-request-body-title} `closure_type`:: diff --git a/docs/api/cases/cases-api-update-comment.asciidoc b/docs/api/cases/cases-api-update-comment.asciidoc index b749d50a15c86d..127d434602f848 100644 --- a/docs/api/cases/cases-api-update-comment.asciidoc +++ b/docs/api/cases/cases-api-update-comment.asciidoc @@ -29,6 +29,7 @@ The identifier for the case. To retrieve case IDs, use (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === {api-request-body-title} `alertId`:: diff --git a/docs/api/cases/cases-api-update-configuration.asciidoc b/docs/api/cases/cases-api-update-configuration.asciidoc index c1dcb2a71e57cf..4bdaacf1f2355e 100644 --- a/docs/api/cases/cases-api-update-configuration.asciidoc +++ b/docs/api/cases/cases-api-update-configuration.asciidoc @@ -35,6 +35,7 @@ The identifier for the configuration. To retrieve the configuration IDs, use (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === Request body `closure_type`:: diff --git a/docs/api/cases/cases-api-update.asciidoc b/docs/api/cases/cases-api-update.asciidoc index 687622cce8dddf..53703908dde47e 100644 --- a/docs/api/cases/cases-api-update.asciidoc +++ b/docs/api/cases/cases-api-update.asciidoc @@ -25,6 +25,7 @@ You must have `all` privileges for the *Cases* feature in the *Management*, (Optional, string) An identifier for the space. If it is not specified, the default space is used. +[role="child_attributes"] === {api-request-body-title} `cases`:: @@ -40,12 +41,13 @@ default space is used. [%collapsible%open] ===== `fields`:: -(Required, object) An object containing the connector fields. +(Required, object) An object containing the connector fields. To remove the +connector, specify `null`. If you want to omit any individual field, specify +`null` as its value. + --- -To remove the connector, specify `null`. If you want to omit any individual -field, specify `null` as its value. - +.Properties of `fields` +[%collapsible%open] +======= For {ibm-r} connectors, specify: `issueTypes`::: @@ -110,7 +112,7 @@ For {swimlane} connectors, specify: `caseId`::: (Required, string) The identifier for the case. --- +======= `id`:: (Required, string) The identifier for the connector. To remove the connector, From d0048b4d1eec27466cf8646c5ed674a15526f0d2 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Thu, 11 Aug 2022 10:44:06 -0600 Subject: [PATCH 25/59] [Security Solution] Fix `narrowDateRange` and `updateDateRange` misuse (#138523) --- .../components/stat_items/index.test.tsx | 6 ++-- .../common/components/stat_items/index.tsx | 12 +++---- .../anomalies_query_tab_body/index.tsx | 2 -- .../anomalies_query_tab_body/types.ts | 4 --- .../components/kpi_hosts/common/index.tsx | 8 ++--- .../components/kpi_hosts/hosts/index.test.tsx | 2 +- .../components/kpi_hosts/hosts/index.tsx | 4 +-- .../hosts/components/kpi_hosts/index.tsx | 10 +++--- .../hosts/components/kpi_hosts/types.ts | 2 +- .../kpi_hosts/unique_ips/index.test.tsx | 2 +- .../components/kpi_hosts/unique_ips/index.tsx | 4 +-- .../hosts/pages/details/details_tabs.test.tsx | 3 +- .../hosts/pages/details/details_tabs.tsx | 34 +----------------- .../public/hosts/pages/details/index.tsx | 27 ++++++++------ .../public/hosts/pages/details/types.ts | 5 --- .../public/hosts/pages/hosts.tsx | 5 ++- .../public/hosts/pages/hosts_tabs.tsx | 35 +------------------ .../public/hosts/pages/navigation/types.ts | 4 --- .../public/hosts/pages/types.ts | 8 ----- .../__snapshots__/index.test.tsx.snap | 2 +- .../components/kpi_network/dns/index.test.tsx | 2 +- .../components/kpi_network/dns/index.tsx | 4 +-- .../components/kpi_network/index.test.tsx | 2 +- .../network/components/kpi_network/index.tsx | 12 +++---- .../network/components/kpi_network/mock.ts | 4 +-- .../kpi_network/network_events/index.test.tsx | 2 +- .../kpi_network/network_events/index.tsx | 4 +-- .../kpi_network/tls_handshakes/index.test.tsx | 2 +- .../kpi_network/tls_handshakes/index.tsx | 4 +-- .../network/components/kpi_network/types.ts | 2 +- .../kpi_network/unique_flows/index.test.tsx | 2 +- .../kpi_network/unique_flows/index.tsx | 4 +-- .../unique_private_ips/index.test.tsx | 2 +- .../kpi_network/unique_private_ips/index.tsx | 4 +-- .../network/pages/details/details_tabs.tsx | 4 +-- .../public/network/pages/details/index.tsx | 1 - .../pages/navigation/network_routes.tsx | 34 +----------------- .../public/network/pages/navigation/types.ts | 4 --- .../public/network/pages/network.tsx | 5 ++- .../kpi_users/authentications/index.test.tsx | 2 +- .../kpi_users/authentications/index.tsx | 4 +-- .../users/components/kpi_users/index.tsx | 6 ++-- .../kpi_users/total_users/index.test.tsx | 2 +- .../kpi_users/total_users/index.tsx | 4 +-- .../users/components/kpi_users/types.ts | 2 +- .../users/pages/details/details_tabs.tsx | 35 +------------------ .../public/users/pages/details/index.tsx | 26 ++++++++------ .../public/users/pages/details/types.ts | 5 --- .../public/users/pages/types.ts | 7 ---- .../public/users/pages/users.tsx | 5 ++- .../public/users/pages/users_tabs.tsx | 35 +------------------ 51 files changed, 106 insertions(+), 304 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/stat_items/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/stat_items/index.test.tsx index f5746b2cae4d0b..ee3271af7a6afa 100644 --- a/x-pack/plugins/security_solution/public/common/components/stat_items/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/stat_items/index.test.tsx @@ -26,7 +26,7 @@ import { mockData, mockEnableChartsData, mockNoChartMappings, - mockNarrowDateRange, + mockUpdateDateRange, } from '../../../network/components/kpi_network/mock'; import { createSecuritySolutionStorageMock, @@ -75,7 +75,7 @@ describe('Stat Items Component', () => { loading: false, setQuerySkip: mockSetQuerySkip, to, - narrowDateRange: mockNarrowDateRange, + updateDateRange: mockUpdateDateRange, }; beforeEach(() => { jest.clearAllMocks(); @@ -281,7 +281,7 @@ describe('useKpiMatrixStatus', () => { 'statItem', from, to, - mockNarrowDateRange, + mockUpdateDateRange, mockSetQuerySkip, false ); diff --git a/x-pack/plugins/security_solution/public/common/components/stat_items/index.tsx b/x-pack/plugins/security_solution/public/common/components/stat_items/index.tsx index 429a86dd8a8a92..50e655d785d309 100644 --- a/x-pack/plugins/security_solution/public/common/components/stat_items/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/stat_items/index.tsx @@ -96,7 +96,7 @@ export interface StatItemsProps extends StatItems { barChart?: ChartSeriesData[]; from: string; id: string; - narrowDateRange: UpdateDateRange; + updateDateRange: UpdateDateRange; to: string; showInspectButton?: boolean; loading: boolean; @@ -193,7 +193,7 @@ export const useKpiMatrixStatus = ( id: string, from: string, to: string, - narrowDateRange: UpdateDateRange, + updateDateRange: UpdateDateRange, setQuerySkip: (skip: boolean) => void, loading: boolean ): StatItemsProps[] => @@ -207,7 +207,7 @@ export const useKpiMatrixStatus = ( statKey: `${stat.key}`, from, to, - narrowDateRange, + updateDateRange, setQuerySkip, loading, })); @@ -228,7 +228,7 @@ export const StatItemsComponent = React.memo( loading = false, showInspectButton = true, index, - narrowDateRange, + updateDateRange, statKey = 'item', to, barChartLensAttributes, @@ -373,7 +373,7 @@ export const StatItemsComponent = React.memo( areaChart={areaChart} configs={areachartConfigs({ xTickFormatter: histogramDateTimeFormatter([from, to]), - onBrushEnd: narrowDateRange, + onBrushEnd: updateDateRange, })} visualizationActionsOptions={{ lensAttributes: areaChartLensAttributes, @@ -403,7 +403,7 @@ export const StatItemsComponent = React.memo( prevProps.setQuerySkip === nextProps.setQuerySkip && prevProps.id === nextProps.id && prevProps.index === nextProps.index && - prevProps.narrowDateRange === nextProps.narrowDateRange && + prevProps.updateDateRange === nextProps.updateDateRange && prevProps.statKey === nextProps.statKey && prevProps.to === nextProps.to && deepEqual(prevProps.areaChart, nextProps.areaChart) && diff --git a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx index f47aa6150967fb..c3eaf31e2d292e 100644 --- a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx @@ -24,7 +24,6 @@ const AnomaliesQueryTabBodyComponent: React.FC = ({ skip, startDate, type, - narrowDateRange, filterQuery, anomaliesFilterQuery, AnomaliesTableComponent, @@ -71,7 +70,6 @@ const AnomaliesQueryTabBodyComponent: React.FC = ({ endDate={endDate} skip={skip} type={type} - narrowDateRange={narrowDateRange} flowTarget={flowTarget} ip={ip} hostName={hostName} diff --git a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts index 797927f6621c2c..59c5f6947537b6 100644 --- a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts +++ b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/types.ts @@ -6,8 +6,6 @@ */ import type { ESTermQuery } from '../../../../../common/typed_json'; -import type { NarrowDateRange } from '../../../components/ml/types'; -import type { UpdateDateRange } from '../../../components/charts/common'; import type { GlobalTimeArgs } from '../../use_global_time'; import type { HostsType } from '../../../../hosts/store/model'; import type { NetworkType } from '../../../../network/store/model'; @@ -27,11 +25,9 @@ export type AnomaliesQueryTabBodyProps = QueryTabBodyProps & { endDate: GlobalTimeArgs['to']; flowTarget?: FlowTargetSourceDest; indexNames: string[]; - narrowDateRange: NarrowDateRange; setQuery: GlobalTimeArgs['setQuery']; startDate: GlobalTimeArgs['from']; skip: boolean; - updateDateRange?: UpdateDateRange; hideHistogramIfEmpty?: boolean; ip?: string; hostName?: string; diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/common/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/common/index.tsx index 8144bd7dde4586..0c4e8524deae13 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/common/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/common/index.tsx @@ -35,19 +35,19 @@ interface KpiBaseComponentProps { id: string; from: string; to: string; - narrowDateRange: UpdateDateRange; + updateDateRange: UpdateDateRange; setQuerySkip: (skip: boolean) => void; } export const KpiBaseComponent = React.memo( - ({ fieldsMapping, data, id, loading = false, from, to, narrowDateRange, setQuerySkip }) => { + ({ fieldsMapping, data, id, loading = false, from, to, updateDateRange, setQuerySkip }) => { const statItemsProps: StatItemsProps[] = useKpiMatrixStatus( fieldsMapping, data, id, from, to, - narrowDateRange, + updateDateRange, setQuerySkip, loading ); @@ -66,7 +66,7 @@ export const KpiBaseComponent = React.memo( prevProps.loading === nextProps.loading && prevProps.from === nextProps.from && prevProps.to === nextProps.to && - prevProps.narrowDateRange === nextProps.narrowDateRange && + prevProps.updateDateRange === nextProps.updateDateRange && deepEqual(prevProps.data, nextProps.data) ); diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.test.tsx index 5b03586b865137..acc71a761079ea 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.test.tsx @@ -25,7 +25,7 @@ describe('Hosts KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.tsx index 390faf57eeb72a..41ebcc6dff629b 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/hosts/index.tsx @@ -40,7 +40,7 @@ const HostsKpiHostsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -66,7 +66,7 @@ const HostsKpiHostsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/index.tsx index 833562dfa7f1fd..9f4e7b41a1c153 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/index.tsx @@ -17,7 +17,7 @@ import * as i18n from './translations'; import { useHostRiskScore } from '../../../risk_score/containers'; export const HostsKpiComponent = React.memo( - ({ filterQuery, from, indexNames, to, setQuery, skip, narrowDateRange }) => { + ({ filterQuery, from, indexNames, to, setQuery, skip, updateDateRange }) => { const [_, { isModuleEnabled }] = useHostRiskScore({}); return ( @@ -53,7 +53,7 @@ export const HostsKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -64,7 +64,7 @@ export const HostsKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -78,7 +78,7 @@ export const HostsKpiComponent = React.memo( HostsKpiComponent.displayName = 'HostsKpiComponent'; export const HostsDetailsKpiComponent = React.memo( - ({ filterQuery, from, indexNames, to, setQuery, skip, narrowDateRange }) => { + ({ filterQuery, from, indexNames, to, setQuery, skip, updateDateRange }) => { return ( @@ -87,7 +87,7 @@ export const HostsDetailsKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/types.ts b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/types.ts index 394b965e543fc0..dcbd04b099dfd4 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/types.ts @@ -13,7 +13,7 @@ export interface HostsKpiProps { from: string; to: string; indexNames: string[]; - narrowDateRange: UpdateDateRange; + updateDateRange: UpdateDateRange; setQuery: GlobalTimeArgs['setQuery']; skip: boolean; } diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.test.tsx index 0e82bf5b39a1b9..d592ee6455a628 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.test.tsx @@ -25,7 +25,7 @@ describe('Unique IPs KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.tsx index 8ffd5d90dc6333..9ad432aee6db89 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/unique_ips/index.tsx @@ -55,7 +55,7 @@ const HostsKpiUniqueIpsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -81,7 +81,7 @@ const HostsKpiUniqueIpsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx index e40c32883e0cdb..46aeae3d41d15c 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.test.tsx @@ -12,7 +12,7 @@ import useResizeObserver from 'use-resize-observer/polyfilled'; import '../../../common/mock/match_media'; import { mockIndexPattern, TestProviders } from '../../../common/mock'; import { HostDetailsTabs } from './details_tabs'; -import type { HostDetailsTabsProps, SetAbsoluteRangeDatePicker } from './types'; +import type { HostDetailsTabsProps } from './types'; import { hostDetailsPagePath } from '../types'; import { type } from './utils'; import { useMountAppended } from '../../../common/utils/use_mount_appended'; @@ -102,7 +102,6 @@ describe('body', () => { isInitializing={false} detailName={'host-1'} setQuery={jest.fn()} - setAbsoluteRangeDatePicker={jest.fn() as unknown as SetAbsoluteRangeDatePicker} hostDetailsPagePath={hostDetailsPagePath} indexNames={[]} indexPattern={mockIndexPattern} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx index 4036f59ad52b6d..81855eedd2f802 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx @@ -5,13 +5,10 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; -import type { UpdateDateRange } from '../../../common/components/charts/common'; -import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; -import type { Anomaly } from '../../../common/components/ml/types'; import { HostsTableType } from '../../store/model'; import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anomalies_query_tab_body'; import { useGlobalTime } from '../../../common/containers/use_global_time'; @@ -38,36 +35,9 @@ export const HostDetailsTabs = React.memo( indexNames, indexPattern, pageFilters = [], - setAbsoluteRangeDatePicker, hostDetailsPagePath, }) => { const { from, to, isInitializing, deleteQuery, setQuery } = useGlobalTime(); - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - - const updateDateRange = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [min, max] = x; - setAbsoluteRangeDatePicker({ - id: 'global', - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - }); - }, - [setAbsoluteRangeDatePicker] - ); const tabProps = { deleteQuery, @@ -80,8 +50,6 @@ export const HostDetailsTabs = React.memo( indexPattern, indexNames, hostName: detailName, - narrowDateRange, - updateDateRange, }; const externalAlertPageFilters = useMemo( diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index d0525b5814864f..9592fd01ae543c 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -83,7 +83,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta ); const getFilters = () => [...hostDetailsPageFilters, ...filters]; - const narrowDateRange = useCallback( + const updateDateRange = useCallback( ({ x }) => { if (!x) { return; @@ -99,6 +99,19 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta }, [dispatch] ); + const narrowDateRange = useCallback( + (score, interval) => { + const fromTo = scoreIntervalToDateTime(score, interval); + dispatch( + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }) + ); + }, + [dispatch] + ); const { indexPattern, indicesExist, selectedPatterns } = useSourcererDataView(); const [loading, { inspect, hostDetails: hostOverview, id, refetch }] = useHostDetails({ @@ -165,14 +178,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta loading={loading} startDate={from} endDate={to} - narrowDateRange={(score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }} + narrowDateRange={narrowDateRange} setQuery={setQuery} refetch={refetch} inspect={inspect} @@ -190,7 +196,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta indexNames={selectedPatterns} setQuery={setQuery} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} skip={isInitializing} /> @@ -220,7 +226,6 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta filterQuery={filterQuery} hostDetailsPagePath={hostDetailsPagePath} indexPattern={indexPattern} - setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker} /> diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts index 118a60c27b0173..858d079252be12 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/types.ts @@ -15,11 +15,6 @@ import type { KeyHostsNavTabWithoutMlPermission } from '../navigation/types'; import type { hostsModel } from '../../store'; interface HostBodyComponentDispatchProps { - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: string; - to: string; - }>; detailName: string; hostDetailsPagePath: string; } diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index 1b04e0c63edacc..077ea01df65e92 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -108,7 +108,7 @@ const HostsComponent = () => { } return filters; }, [severitySelection, tabName, filters]); - const narrowDateRange = useCallback( + const updateDateRange = useCallback( ({ x }) => { if (!x) { return; @@ -204,7 +204,7 @@ const HostsComponent = () => { setQuery={setQuery} to={to} skip={isInitializing || !filterQuery} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} /> @@ -225,7 +225,6 @@ const HostsComponent = () => { filterQuery={tabsFilterQuery || ''} isInitializing={isInitializing} indexNames={selectedPatterns} - setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker} setQuery={setQuery} from={from} type={hostsModel.HostsType.page} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx index a06aa4b0aadc3c..5ffc54e227d7cc 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts_tabs.tsx @@ -5,17 +5,14 @@ * 2.0. */ -import React, { memo, useCallback, useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; import type { HostsTabsProps } from './types'; -import { scoreIntervalToDateTime } from '../../common/components/ml/score/score_interval_to_datetime'; -import type { Anomaly } from '../../common/components/ml/types'; import { HostsTableType } from '../store/model'; import { AnomaliesQueryTabBody } from '../../common/containers/anomalies/anomalies_query_tab_body'; import { AnomaliesHostTable } from '../../common/components/ml/tables/anomalies_host_table'; -import type { UpdateDateRange } from '../../common/components/charts/common'; import { EventsQueryTabBody } from '../../common/components/events_tab'; import { HOSTS_PATH } from '../../../common/constants'; @@ -36,38 +33,10 @@ export const HostsTabs = memo( from, indexNames, isInitializing, - setAbsoluteRangeDatePicker, setQuery, to, type, }) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - - const updateDateRange = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [min, max] = x; - setAbsoluteRangeDatePicker({ - id: 'global', - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - }); - }, - [setAbsoluteRangeDatePicker] - ); - const tabProps = { deleteQuery, endDate: to, @@ -77,8 +46,6 @@ export const HostsTabs = memo( setQuery, startDate: from, type, - narrowDateRange, - updateDateRange, }; const externalAlertPageFilters = useMemo( diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts index 04998089926867..7128ab76e412ac 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/types.ts @@ -8,11 +8,9 @@ import type { Filter } from '@kbn/es-query'; import type { ESTermQuery } from '../../../../common/typed_json'; -import type { NarrowDateRange } from '../../../common/components/ml/types'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import type { HostsTableType, HostsType } from '../../store/model'; import type { NavTab } from '../../../common/components/navigation/types'; -import type { UpdateDateRange } from '../../../common/components/charts/common'; export type KeyHostsNavTabWithoutMlPermission = HostsTableType.hosts & HostsTableType.authentications & @@ -38,8 +36,6 @@ export type HostsComponentsQueryProps = QueryTabBodyProps & { pageFilters?: Filter[]; skip: boolean; setQuery: GlobalTimeArgs['setQuery']; - updateDateRange?: UpdateDateRange; - narrowDateRange?: NarrowDateRange; }; export type AlertsComponentQueryProps = HostsComponentsQueryProps & { diff --git a/x-pack/plugins/security_solution/public/hosts/pages/types.ts b/x-pack/plugins/security_solution/public/hosts/pages/types.ts index 17e2af205f7995..e16ccfa100fb41 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/types.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/types.ts @@ -5,12 +5,9 @@ * 2.0. */ -import type { ActionCreator } from 'typescript-fsa'; - import type { Filter } from '@kbn/es-query'; import type { hostsModel } from '../store'; import type { GlobalTimeArgs } from '../../common/containers/use_global_time'; -import type { InputsModelId } from '../../common/store/inputs/constants'; import { HOSTS_PATH } from '../../../common/constants'; export const hostDetailsPagePath = `${HOSTS_PATH}/name/:detailName`; @@ -20,11 +17,6 @@ export type HostsTabsProps = GlobalTimeArgs & { pageFilters?: Filter[]; indexNames: string[]; type: hostsModel.HostsType; - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: string; - to: string; - }>; }; export type HostsQueryProps = GlobalTimeArgs; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/kpi_network/__snapshots__/index.test.tsx.snap index c512bd99a79165..c7505367231792 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/__snapshots__/index.test.tsx.snap @@ -5,9 +5,9 @@ exports[`NetworkKpiComponent rendering it renders the default widget 1`] = ` filterQuery="" from="2019-06-15T06:00:00.000Z" indexNames={Array []} - narrowDateRange={[MockFunction]} setQuery={[MockFunction]} skip={true} to="2019-06-18T06:00:00.000Z" + updateDateRange={[MockFunction]} /> `; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.test.tsx index e055154728e85e..bc3fc3bd3c62cb 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.test.tsx @@ -25,7 +25,7 @@ describe('DNS KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.tsx index 8a5073ce2edc0f..e547571ea2f99f 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/dns/index.tsx @@ -35,7 +35,7 @@ const NetworkKpiDnsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -61,7 +61,7 @@ const NetworkKpiDnsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/index.test.tsx index e322ea0ee899d9..f3460f8cbea1d3 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/index.test.tsx @@ -26,7 +26,7 @@ describe('NetworkKpiComponent', () => { filterQuery: '', from: '2019-06-15T06:00:00.000Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: true, to: '2019-06-18T06:00:00.000Z', diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/index.tsx index 8b4c7d30bb8ecc..b6b87e9193dd28 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/index.tsx @@ -16,7 +16,7 @@ import { NetworkKpiUniquePrivateIps } from './unique_private_ips'; import type { NetworkKpiProps } from './types'; export const NetworkKpiComponent = React.memo( - ({ filterQuery, from, indexNames, to, setQuery, skip, narrowDateRange }) => ( + ({ filterQuery, from, indexNames, to, setQuery, skip, updateDateRange }) => ( @@ -26,7 +26,7 @@ export const NetworkKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -37,7 +37,7 @@ export const NetworkKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -51,7 +51,7 @@ export const NetworkKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -62,7 +62,7 @@ export const NetworkKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -75,7 +75,7 @@ export const NetworkKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/mock.ts b/x-pack/plugins/security_solution/public/network/components/kpi_network/mock.ts index 07ff974e1f3c7d..949bf35879ab5f 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/mock.ts +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/mock.ts @@ -12,7 +12,7 @@ import { kpiUniquePrivateIpsBarLensAttributes } from '../../../common/components import { kpiUniquePrivateIpsDestinationMetricLensAttributes } from '../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_destination_metric'; import { kpiUniquePrivateIpsSourceMetricLensAttributes } from '../../../common/components/visualization_actions/lens_attributes/network/kpi_unique_private_ips_source_metric'; -export const mockNarrowDateRange = jest.fn(); +export const mockUpdateDateRange = jest.fn(); export const mockData: NetworkKpiStrategyResponse = { networkEvents: 16, @@ -152,7 +152,7 @@ export const mockEnableChartsData = { statKey: 'UniqueIps', setQuerySkip: jest.fn(), to: '2019-06-18T06:00:00.000Z', - narrowDateRange: mockNarrowDateRange, + updateDateRange: mockUpdateDateRange, areaChartLensAttributes: kpiUniquePrivateIpsAreaLensAttributes, barChartLensAttributes: kpiUniquePrivateIpsBarLensAttributes, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.test.tsx index 4b27cff48ac4e3..2585d2e67314d7 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.test.tsx @@ -25,7 +25,7 @@ describe('Network Events KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.tsx index e01615697ac530..5dda2f167c7e29 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/network_events/index.tsx @@ -39,7 +39,7 @@ const NetworkKpiNetworkEventsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -65,7 +65,7 @@ const NetworkKpiNetworkEventsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.test.tsx index 3af02cb1d17cbe..f177cc850bdcb2 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.test.tsx @@ -25,7 +25,7 @@ describe('TLS Handshakes KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.tsx index ee1409fe4d3161..27fe5d9b39e657 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/tls_handshakes/index.tsx @@ -34,7 +34,7 @@ const NetworkKpiTlsHandshakesComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -60,7 +60,7 @@ const NetworkKpiTlsHandshakesComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/types.ts b/x-pack/plugins/security_solution/public/network/components/kpi_network/types.ts index b15d05ebc3c73f..5f3e824f5c2bd3 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/types.ts +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/types.ts @@ -13,7 +13,7 @@ export interface NetworkKpiProps { from: string; indexNames: string[]; to: string; - narrowDateRange: UpdateDateRange; + updateDateRange: UpdateDateRange; setQuery: GlobalTimeArgs['setQuery']; skip: boolean; } diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.test.tsx index 5f5da4e3c1ba12..5a0c13a37e82d8 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.test.tsx @@ -25,7 +25,7 @@ describe('Unique Flows KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.tsx index 8db91826721abc..9f05dfcf26af90 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_flows/index.tsx @@ -34,7 +34,7 @@ const NetworkKpiUniqueFlowsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -60,7 +60,7 @@ const NetworkKpiUniqueFlowsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.test.tsx index 03ad5b9ee6e3c8..43559ed898c7b6 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.test.tsx @@ -25,7 +25,7 @@ describe('Unique Private IPs KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.tsx b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.tsx index fd5f24fc1b5ebd..7457c6b033197d 100644 --- a/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/kpi_network/unique_private_ips/index.tsx @@ -62,7 +62,7 @@ const NetworkKpiUniquePrivateIpsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -88,7 +88,7 @@ const NetworkKpiUniquePrivateIpsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx index 82e206ce66f935..95407f2374b5ab 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/details_tabs.tsx @@ -41,13 +41,12 @@ interface NetworkDetailTabsProps { indexNames: string[]; skip: boolean; setQuery: GlobalTimeArgs['setQuery']; - narrowDateRange: (score: unknown, interval: unknown) => void; indexPattern: DataViewBase; flowTarget: FlowTargetSourceDest; } export const NetworkDetailsTabs = React.memo( - ({ narrowDateRange, indexPattern, flowTarget, ...rest }) => { + ({ indexPattern, flowTarget, ...rest }) => { const type = networkModel.NetworkType.details; const commonProps = { ...rest, type }; @@ -111,7 +110,6 @@ export const NetworkDetailsTabs = React.memo( {...commonPropsWithFlowTarget} hideHistogramIfEmpty={true} AnomaliesTableComponent={AnomaliesNetworkTable} - narrowDateRange={narrowDateRange} /> { indexNames={selectedPatterns} skip={shouldSkip} setQuery={setQuery} - narrowDateRange={narrowDateRange} indexPattern={indexPattern} flowTarget={flowTarget} /> diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx b/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx index 0e7d55b4af10f6..80c83e4d9f2189 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/network_routes.tsx @@ -5,13 +5,12 @@ * 2.0. */ -import React, { useCallback } from 'react'; +import React from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; import { EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { FlowTargetSourceDest } from '../../../../common/search_strategy/security_solution/network'; -import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; import { CountriesQueryTabBody, @@ -28,8 +27,6 @@ import { TimelineId } from '../../../../common/types'; import { ConditionalFlexGroup } from './conditional_flex_group'; import type { NetworkRoutesProps } from './types'; import { NetworkRouteType } from './types'; -import type { Anomaly } from '../../../common/components/ml/types'; -import type { UpdateDateRange } from '../../../common/components/charts/common'; import { NETWORK_PATH } from '../../../../common/constants'; export const NetworkRoutes = React.memo( @@ -43,34 +40,7 @@ export const NetworkRoutes = React.memo( indexPattern, indexNames, setQuery, - setAbsoluteRangeDatePicker, }) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - const updateDateRange = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [min, max] = x; - setAbsoluteRangeDatePicker({ - id: 'global', - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - }); - }, - [setAbsoluteRangeDatePicker] - ); - const networkAnomaliesFilterQuery = { bool: { should: [ @@ -95,7 +65,6 @@ export const NetworkRoutes = React.memo( indexNames, skip: isInitializing, type, - narrowDateRange, setQuery, filterQuery, }; @@ -103,7 +72,6 @@ export const NetworkRoutes = React.memo( const tabProps = { ...commonProps, indexPattern, - updateDateRange, }; const anomaliesProps = { diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts index 6530296949f865..e2b96fce68b6e6 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts @@ -8,7 +8,6 @@ import type { DataViewBase } from '@kbn/es-query'; import type { Optional } from 'utility-types'; -import type { NarrowDateRange } from '../../../common/components/ml/types'; import type { ESTermQuery } from '../../../../common/typed_json'; import type { NavTab } from '../../../common/components/navigation/types'; @@ -16,7 +15,6 @@ import type { FlowTargetSourceDest } from '../../../../common/search_strategy/se import type { networkModel } from '../../store'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; -import type { SetAbsoluteRangeDatePicker } from '../types'; import type { DocValueFields } from '../../../common/containers/source'; export interface QueryTabBodyProps extends Pick { @@ -24,7 +22,6 @@ export interface QueryTabBodyProps extends Pick( return filters; }, [tabName, filters]); - const narrowDateRange = useCallback( + const updateDateRange = useCallback( ({ x }) => { if (!x) { return; @@ -198,7 +198,7 @@ const NetworkComponent = React.memo( filterQuery={filterQuery} from={from} indexNames={selectedPatterns} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={isInitializing || filterQuery === undefined} to={to} @@ -221,7 +221,6 @@ const NetworkComponent = React.memo( indexPattern={indexPattern} indexNames={selectedPatterns} setQuery={setQuery} - setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker} type={networkModel.NetworkType.page} to={to} /> diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.test.tsx b/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.test.tsx index e3662dc164e34e..2bc2bbbad82110 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.test.tsx +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.test.tsx @@ -25,7 +25,7 @@ describe('Authentications KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.tsx b/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.tsx index aafeb29e9d1165..4a9b049773ba01 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.tsx +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/authentications/index.tsx @@ -59,7 +59,7 @@ const UsersKpiAuthenticationsComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -85,7 +85,7 @@ const UsersKpiAuthenticationsComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/index.tsx b/x-pack/plugins/security_solution/public/users/components/kpi_users/index.tsx index 909bb44829e65a..72e004c2d340d9 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/index.tsx +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/index.tsx @@ -18,7 +18,7 @@ import * as i18n from './translations'; import { RISKY_USERS_DOC_LINK } from '../constants'; export const UsersKpiComponent = React.memo( - ({ filterQuery, from, indexNames, to, setQuery, skip, narrowDateRange }) => { + ({ filterQuery, from, indexNames, to, setQuery, skip, updateDateRange }) => { const [_, { isModuleEnabled }] = useUserRiskScore({}); return ( @@ -54,7 +54,7 @@ export const UsersKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> @@ -66,7 +66,7 @@ export const UsersKpiComponent = React.memo( from={from} indexNames={indexNames} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} setQuery={setQuery} skip={skip} /> diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.test.tsx b/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.test.tsx index 94c2c6b5755f70..944d90c423b722 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.test.tsx +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.test.tsx @@ -25,7 +25,7 @@ describe('Total Users KPI', () => { from: '2019-06-25T04:31:59.345Z', to: '2019-06-25T06:31:59.345Z', indexNames: [], - narrowDateRange: jest.fn(), + updateDateRange: jest.fn(), setQuery: jest.fn(), skip: false, }; diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.tsx b/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.tsx index df5a7208930bc9..35d8864dc977eb 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.tsx +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/total_users/index.tsx @@ -45,7 +45,7 @@ const TotalUsersKpiComponent: React.FC = ({ from, indexNames, to, - narrowDateRange, + updateDateRange, setQuery, skip, }) => { @@ -85,7 +85,7 @@ const TotalUsersKpiComponent: React.FC = ({ fieldsMapping={fieldsMapping} from={from} to={to} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} refetch={refetch} setQuery={setQuery} setQuerySkip={setQuerySkip} diff --git a/x-pack/plugins/security_solution/public/users/components/kpi_users/types.ts b/x-pack/plugins/security_solution/public/users/components/kpi_users/types.ts index ddc689bcbafe8d..0c0c3642365ae3 100644 --- a/x-pack/plugins/security_solution/public/users/components/kpi_users/types.ts +++ b/x-pack/plugins/security_solution/public/users/components/kpi_users/types.ts @@ -13,7 +13,7 @@ export interface UsersKpiProps { from: string; to: string; indexNames: string[]; - narrowDateRange: UpdateDateRange; + updateDateRange: UpdateDateRange; setQuery: GlobalTimeArgs['setQuery']; skip: boolean; } diff --git a/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx index da3aa5d5855175..89677ede45f879 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/details_tabs.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -13,9 +13,6 @@ import { UsersTableType } from '../../store/model'; import { AnomaliesUserTable } from '../../../common/components/ml/tables/anomalies_user_table'; import type { UsersDetailsTabsProps } from './types'; import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anomalies_query_tab_body'; -import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; -import type { UpdateDateRange } from '../../../common/components/charts/common'; -import type { Anomaly } from '../../../common/components/ml/types'; import { usersDetailsPagePath } from '../constants'; import { TimelineId } from '../../../../common/types'; import { EventsQueryTabBody } from '../../../common/components/events_tab'; @@ -33,37 +30,9 @@ export const UsersDetailsTabs = React.memo( setQuery, to, type, - setAbsoluteRangeDatePicker, detailName, pageFilters = [], }) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - - const updateDateRange = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [min, max] = x; - setAbsoluteRangeDatePicker({ - id: 'global', - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - }); - }, - [setAbsoluteRangeDatePicker] - ); - const tabProps = { deleteQuery, endDate: to, @@ -73,8 +42,6 @@ export const UsersDetailsTabs = React.memo( setQuery, startDate: from, type, - narrowDateRange, - updateDateRange, userName: detailName, }; diff --git a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx index e0fe59d9a16679..5eeb7d00fcc2b7 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx @@ -7,7 +7,7 @@ import { EuiSpacer, EuiWindowEvent } from '@elastic/eui'; import { noop } from 'lodash/fp'; -import React, { useEffect, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import type { Filter } from '@kbn/es-query'; @@ -118,6 +118,20 @@ const UsersDetailsComponent: React.FC = ({ useQueryInspector({ setQuery, deleteQuery, refetch, inspect, loading, queryId: QUERY_ID }); + const narrowDateRange = useCallback( + (score, interval) => { + const fromTo = scoreIntervalToDateTime(score, interval); + dispatch( + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }) + ); + }, + [dispatch] + ); + return ( <> {indicesExist ? ( @@ -156,14 +170,7 @@ const UsersDetailsComponent: React.FC = ({ loading={loading} startDate={from} endDate={to} - narrowDateRange={(score, interval) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }} + narrowDateRange={narrowDateRange} indexPatterns={selectedPatterns} /> )} @@ -190,7 +197,6 @@ const UsersDetailsComponent: React.FC = ({ indexPattern={indexPattern} isInitializing={isInitializing} pageFilters={usersDetailsPageFilters} - setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker} setQuery={setQuery} to={to} type={type} diff --git a/x-pack/plugins/security_solution/public/users/pages/details/types.ts b/x-pack/plugins/security_solution/public/users/pages/details/types.ts index 0046f3da7d63b4..12106aaf4cc06a 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/details/types.ts @@ -22,11 +22,6 @@ interface UsersDetailsComponentReduxProps { } interface UserBodyComponentDispatchProps { - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: string; - to: string; - }>; detailName: string; usersDetailsPagePath: string; } diff --git a/x-pack/plugins/security_solution/public/users/pages/types.ts b/x-pack/plugins/security_solution/public/users/pages/types.ts index 0f196e90090700..b7af4c3c54d22f 100644 --- a/x-pack/plugins/security_solution/public/users/pages/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/types.ts @@ -4,14 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { ActionCreator } from 'typescript-fsa'; import type { Filter } from '@kbn/es-query'; import type { DocValueFields } from '@kbn/timelines-plugin/common'; import type { GlobalTimeArgs } from '../../common/containers/use_global_time'; import type { usersModel } from '../store'; -import type { InputsModelId } from '../../common/store/inputs/constants'; export type UsersTabsProps = GlobalTimeArgs & { docValueFields: DocValueFields[]; @@ -19,11 +17,6 @@ export type UsersTabsProps = GlobalTimeArgs & { pageFilters?: Filter[]; indexNames: string[]; type: usersModel.UsersType; - setAbsoluteRangeDatePicker: ActionCreator<{ - id: InputsModelId; - from: string; - to: string; - }>; }; export type UsersQueryProps = GlobalTimeArgs; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index 9ac8efc0e83c40..9d567e76050749 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -150,7 +150,7 @@ const UsersComponent = () => { [containerElement, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable] ); - const narrowDateRange = useCallback( + const updateDateRange = useCallback( ({ x }) => { if (!x) { return; @@ -199,7 +199,7 @@ const UsersComponent = () => { setQuery={setQuery} to={to} skip={isInitializing || !filterQuery} - narrowDateRange={narrowDateRange} + updateDateRange={updateDateRange} /> @@ -215,7 +215,6 @@ const UsersComponent = () => { from={from} indexNames={selectedPatterns} isInitializing={isInitializing} - setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker} setQuery={setQuery} to={to} type={usersModel.UsersType.page} diff --git a/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx b/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx index 039831cdb9bbe1..530ea9ffbc568b 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users_tabs.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useCallback } from 'react'; +import React, { memo } from 'react'; import { Switch } from 'react-router-dom'; import { Route } from '@kbn/kibana-react-plugin/public'; @@ -15,9 +15,6 @@ import { USERS_PATH } from '../../../common/constants'; import { AllUsersQueryTabBody, AuthenticationsQueryTabBody } from './navigation'; import { AnomaliesQueryTabBody } from '../../common/containers/anomalies/anomalies_query_tab_body'; import { AnomaliesUserTable } from '../../common/components/ml/tables/anomalies_user_table'; -import type { Anomaly } from '../../common/components/ml/types'; -import { scoreIntervalToDateTime } from '../../common/components/ml/score/score_interval_to_datetime'; -import type { UpdateDateRange } from '../../common/components/charts/common'; import { UserRiskScoreQueryTabBody } from './navigation/user_risk_score_tab_body'; import { EventsQueryTabBody } from '../../common/components/events_tab'; @@ -34,35 +31,7 @@ export const UsersTabs = memo( setQuery, to, type, - setAbsoluteRangeDatePicker, }) => { - const narrowDateRange = useCallback( - (score: Anomaly, interval: string) => { - const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); - }, - [setAbsoluteRangeDatePicker] - ); - - const updateDateRange = useCallback( - ({ x }) => { - if (!x) { - return; - } - const [min, max] = x; - setAbsoluteRangeDatePicker({ - id: 'global', - from: new Date(min).toISOString(), - to: new Date(max).toISOString(), - }); - }, - [setAbsoluteRangeDatePicker] - ); - const tabProps = { deleteQuery, endDate: to, @@ -72,8 +41,6 @@ export const UsersTabs = memo( setQuery, startDate: from, type, - narrowDateRange, - updateDateRange, }; return ( From 826bf645a71b979ee87176160d53bbbd9147e768 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 11 Aug 2022 13:40:15 -0400 Subject: [PATCH 26/59] Bump chromedriver, selenium (#138607) --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index e67bcca74beb76..3906ff723236b8 100644 --- a/package.json +++ b/package.json @@ -1123,7 +1123,7 @@ "callsites": "^3.1.0", "chance": "1.0.18", "chokidar": "^3.5.3", - "chromedriver": "^103.0.0", + "chromedriver": "^104.0.0", "clean-webpack-plugin": "^3.0.0", "compression-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^6.0.2", @@ -1249,7 +1249,7 @@ "resolve": "^1.22.0", "rxjs-marbles": "^5.0.6", "sass-loader": "^10.3.1", - "selenium-webdriver": "^4.3.1", + "selenium-webdriver": "^4.4.0", "simple-git": "^3.10.0", "sinon": "^7.4.2", "sort-package-json": "^1.53.1", diff --git a/yarn.lock b/yarn.lock index d9a9902bbc4d0b..937ef8b66c27f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11366,10 +11366,10 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^103.0.0: - version "103.0.0" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-103.0.0.tgz#2ef086d62076e3ff6df6cfb84895d11d2c18d9cf" - integrity sha512-7BHf6HWt0PeOHCzWO8qlnD13sARzr5AKTtG8Csn+czsuAsajwPxdLNtry5GPh8HYFyl+i0M+yg3bT43AGfgU9w== +chromedriver@^104.0.0: + version "104.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-104.0.0.tgz#2f730f52a567280872567bf3497e1c673b6f4275" + integrity sha512-zbHZutN2ATo19xA6nXwwLn+KueD/5w8ap5m4b6bCb8MIaRFnyDwMbFoy7oFAjlSMpCFL3KSaZRiWUwjj//N3yQ== dependencies: "@testim/chrome-version" "^1.1.2" axios "^0.27.2" @@ -25497,10 +25497,10 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.3.1.tgz#5e9c6c4adee65e57776b5bd4c07c59b65b8f056d" - integrity sha512-TjH/ls1WKRQoFEHcqtn6UtwcLnA3yvx08v9cSSFYvyhp8hJWRtbe9ae2I8uXPisEZ2EaGKKoxBZ4EHv0BJM15g== +selenium-webdriver@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.4.0.tgz#3f280504f6c0ac64a24b176304213b5a49ec2553" + integrity sha512-Du+/xfpvNi9zHAeYgXhOWN9yH0hph+cuX+hHDBr7d+SbtQVcfNJwBzLsbdHrB1Wh7MHXFuIkSG88A9TRRQUx3g== dependencies: jszip "^3.10.0" tmp "^0.2.1" From 12166e01a6487983e9582d9c8717c4978720a64e Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 11 Aug 2022 11:18:53 -0700 Subject: [PATCH 27/59] [Data View Editor] Ensure proper encoding on request to find matching indices for a new Data View (#138587) --- .../public/lib/get_indices.test.ts | 23 ++++++++++++++++++- .../public/lib/get_indices.ts | 15 ++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/plugins/data_view_editor/public/lib/get_indices.test.ts b/src/plugins/data_view_editor/public/lib/get_indices.test.ts index d4003e8bb4575e..4fabb9dcbd49ce 100644 --- a/src/plugins/data_view_editor/public/lib/get_indices.test.ts +++ b/src/plugins/data_view_editor/public/lib/get_indices.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getIndices, responseToItemArray } from './get_indices'; +import { getIndices, getIndicesViaResolve, responseToItemArray } from './get_indices'; import { httpServiceMock } from '@kbn/core/public/mocks'; import { ResolveIndexResponseItemIndexAttrs } from '../types'; @@ -39,6 +39,10 @@ const http = httpServiceMock.createStartContract(); http.get.mockResolvedValue(successfulResolveResponse); describe('getIndices', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should work in a basic case', async () => { const uncalledSearchClient = jest.fn(); const result = await getIndices({ @@ -103,6 +107,23 @@ describe('getIndices', () => { expect(responseToItemArray({}, getTags)).toEqual([]); }); + describe('getIndicesViaResolve', () => { + it('should encode the pattern for a working URI', async () => { + const spy = jest.spyOn(http, 'get'); + const pattern = 'test-%'; + await getIndicesViaResolve({ + http, + pattern, + showAllIndices: true, + isRollupIndex: () => false, + }); + expect(spy).toHaveBeenCalledWith( + '/internal/index-pattern-management/resolve_index/test-%25', + { query: { expand_wildcards: 'all' } } + ); + }); + }); + describe('errors', () => { it('should handle thrown errors gracefully', async () => { http.get.mockImplementationOnce(() => { diff --git a/src/plugins/data_view_editor/public/lib/get_indices.ts b/src/plugins/data_view_editor/public/lib/get_indices.ts index 83b64916cdae91..2c04d6e3899641 100644 --- a/src/plugins/data_view_editor/public/lib/get_indices.ts +++ b/src/plugins/data_view_editor/public/lib/get_indices.ts @@ -50,11 +50,15 @@ export const getIndicesViaResolve = async ({ pattern: string; showAllIndices: boolean; isRollupIndex: (indexName: string) => boolean; -}) => - http - .get(`/internal/index-pattern-management/resolve_index/${pattern}`, { - query: showAllIndices ? { expand_wildcards: 'all' } : undefined, - }) +}) => { + const encodedPattern = encodeURIComponent(pattern); + return http + .get( + `/internal/index-pattern-management/resolve_index/${encodedPattern}`, + { + query: showAllIndices ? { expand_wildcards: 'all' } : undefined, + } + ) .then((response) => { if (!response) { return []; @@ -62,6 +66,7 @@ export const getIndicesViaResolve = async ({ return responseToItemArray(response, getIndexTags(isRollupIndex)); } }); +}; export async function getIndices({ http, From 8f51b55a31147462c1964e60c0bae40850b5a2bb Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 11 Aug 2022 11:19:22 -0700 Subject: [PATCH 28/59] [DataViews] when a mapped field exists sharing a name as a runtime field, specify the mapped field in queries - not the RT field (#138471) * runtime fields vs mapped data * optimizations per feedback --- .../common/data_views/data_view.test.ts | 45 +++++++++++++------ .../data_views/common/data_views/data_view.ts | 25 ++++++++++- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/plugins/data_views/common/data_views/data_view.test.ts b/src/plugins/data_views/common/data_views/data_view.test.ts index b9ac222c3a26f6..bd6890ade9ae2a 100644 --- a/src/plugins/data_views/common/data_views/data_view.test.ts +++ b/src/plugins/data_views/common/data_views/data_view.test.ts @@ -6,19 +6,15 @@ * Side Public License, v 1. */ -import { map, last } from 'lodash'; - -import { DataView } from './data_view'; - +import { FieldFormat } from '@kbn/field-formats-plugin/common'; +import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; import { CharacterNotAllowedInField } from '@kbn/kibana-utils-plugin/common'; - +import { last, map } from 'lodash'; +import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; +import { stubLogstashFields } from '../field.stub'; import { DataViewField } from '../fields'; - -import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; -import { FieldFormat } from '@kbn/field-formats-plugin/common'; import { RuntimeField, RuntimeTypeExceptComposite } from '../types'; -import { stubLogstashFields } from '../field.stub'; -import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; +import { DataView } from './data_view'; class MockFieldFormatter {} @@ -41,7 +37,7 @@ const runtimeField = { type: 'string', }; -fieldFormatsMock.getInstance = jest.fn().mockImplementation(() => new MockFieldFormatter()) as any; +fieldFormatsMock.getInstance = jest.fn().mockImplementation(() => new MockFieldFormatter()); // helper function to create index patterns function create(id: string, spec?: object) { @@ -309,6 +305,29 @@ describe('IndexPattern', () => { expect(indexPattern.toSpec()!.fields!['@tags'].runtimeField).toBeUndefined(); }); + test('ignore runtime field mapping if a mapped field exists with the same name', () => { + expect(indexPattern.getRuntimeMappings()).toEqual({ + runtime_field: { script: { source: "emit('hello world')" }, type: 'keyword' }, + }); + + // add a runtime field called "theme" + indexPattern.addRuntimeField('theme', runtimeWithAttrs); + + // add a new mapped field also called "theme" + indexPattern.fields.add({ + name: 'theme', + type: 'keyword', + aggregatable: true, + searchable: true, + readFromDocValues: false, + isMapped: true, + }); + + expect(indexPattern.getRuntimeMappings()).toEqual({ + runtime_field: { script: { source: "emit('hello world')" }, type: 'keyword' }, + }); + }); + test('add and remove runtime field as new field', () => { indexPattern.addRuntimeField('new_field', runtimeWithAttrs); expect(indexPattern.toSpec().runtimeFieldMap).toEqual({ @@ -354,9 +373,9 @@ describe('IndexPattern', () => { expect(indexPattern.toSpec()!.fields!.new_field).toBeUndefined(); }); - test('should not allow runtime field with * in name', async () => { + test('should not allow runtime field with * in name', () => { try { - await indexPattern.addRuntimeField('test*123', runtime); + indexPattern.addRuntimeField('test*123', runtime); } catch (e) { expect(e).toBeInstanceOf(CharacterNotAllowedInField); } diff --git a/src/plugins/data_views/common/data_views/data_view.ts b/src/plugins/data_views/common/data_views/data_view.ts index c8cafd36fb7429..c5a8abc7fc88ec 100644 --- a/src/plugins/data_views/common/data_views/data_view.ts +++ b/src/plugins/data_views/common/data_views/data_view.ts @@ -496,6 +496,7 @@ export class DataView implements DataViewBase { /** * Get all runtime field definitions. + * NOTE: this does not strip out runtime fields that match mapped field names * @returns map of runtime field definitions by field name */ @@ -582,8 +583,19 @@ export class DataView implements DataViewBase { * Return the "runtime_mappings" section of the ES search query. */ getRuntimeMappings(): estypes.MappingRuntimeFields { - // @ts-expect-error The ES client does not yet include the "composite" runtime type - return _.cloneDeep(this.runtimeFieldMap); + const mappedFields = this.getMappedFieldNames(); + const records = Object.keys(this.runtimeFieldMap).reduce>( + (acc, fieldName) => { + // do not include fields that are mapped + if (!mappedFields.includes(fieldName)) { + acc[fieldName] = this.runtimeFieldMap[fieldName]; + } + + return acc; + }, + {} + ); + return records as estypes.MappingRuntimeFields; } /** @@ -667,6 +679,15 @@ export class DataView implements DataViewBase { delete this.fieldFormatMap[fieldName]; }; + private getMappedFieldNames() { + return this.fields.getAll().reduce((acc, dataViewField) => { + if (dataViewField.isMapped) { + acc.push(dataViewField.name); + } + return acc; + }, []); + } + /** * Add composite runtime field and all subfields. * @param name field name From 94b51c4da5529bd40042a1af520e625f3ffa781a Mon Sep 17 00:00:00 2001 From: liza-mae Date: Thu, 11 Aug 2022 13:02:41 -0600 Subject: [PATCH 29/59] Fix management test to run against cloud (#138656) * Fix test to run against cloud * Keep original names --- .../apps/management/_exclude_index_pattern.ts | 22 ++++++++++++-- test/functional/config.base.js | 30 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/test/functional/apps/management/_exclude_index_pattern.ts b/test/functional/apps/management/_exclude_index_pattern.ts index 32416b52c4a3a9..6a895efb3632fe 100644 --- a/test/functional/apps/management/_exclude_index_pattern.ts +++ b/test/functional/apps/management/_exclude_index_pattern.ts @@ -12,9 +12,12 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['settings']); const es = getService('es'); + const security = getService('security'); describe('creating and deleting default index', function describeIndexTests() { - it('data view creation with exclusion', async () => { + before(async function () { + await security.testUser.setRoles(['kibana_admin', 'index_a', 'index_b']); + await PageObjects.settings.navigateTo(); await es.transport.request({ path: '/index-a/_doc', method: 'POST', @@ -26,13 +29,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { method: 'POST', body: { title: 'hello' }, }); - await PageObjects.settings.createIndexPattern('index-*,-index-b'); + }); + it('data view creation with exclusion', async () => { const fieldCount = await PageObjects.settings.getFieldsTabCount(); - // five metafields plus keyword and text version of 'user' field expect(parseInt(fieldCount, 10)).to.be(6); }); + + after(async () => { + await es.transport.request({ + path: '/index-a', + method: 'DELETE', + }); + await es.transport.request({ + path: '/index-b', + method: 'DELETE', + }); + await PageObjects.settings.removeIndexPattern(); + await security.testUser.restoreDefaults(); + }); }); } diff --git a/test/functional/config.base.js b/test/functional/config.base.js index c79ce9b60bd1ec..dd576cbbd4f495 100644 --- a/test/functional/config.base.js +++ b/test/functional/config.base.js @@ -249,6 +249,36 @@ export default async function ({ readConfigFile }) { kibana: [], }, + index_a: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['index-a'], + privileges: ['read', 'view_index_metadata', 'manage', 'create_index', 'index'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + + index_b: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['index-b'], + privileges: ['read', 'view_index_metadata', 'manage', 'create_index', 'index'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + kibana_sample_read: { elasticsearch: { cluster: [], From e5550d466c88b95b75aa7bd2ab6d0811e232f494 Mon Sep 17 00:00:00 2001 From: "Joey F. Poon" Date: Thu, 11 Aug 2022 14:10:40 -0500 Subject: [PATCH 30/59] [Security Solution] update linux deadlock description + help link (#138561) --- packages/kbn-doc-links/src/get_doc_links.ts | 2 +- .../policy_response/policy_response_friendly_names.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index fe2206033a2b85..ecef81171b241c 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -357,7 +357,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { policyResponseTroubleshooting: { full_disk_access: `${SECURITY_SOLUTION_DOCS}deploy-elastic-endpoint.html#enable-fda-endpoint`, macos_system_ext: `${SECURITY_SOLUTION_DOCS}deploy-elastic-endpoint.html#system-extension-endpoint`, - linux_deadlock: `${SECURITY_SOLUTION_DOCS}ts-management.html`, + linux_deadlock: `${SECURITY_SOLUTION_DOCS}ts-management.html#linux-deadlock`, }, responseActions: `${SECURITY_SOLUTION_DOCS}response-actions.html`, }, diff --git a/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_friendly_names.ts b/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_friendly_names.ts index e7ac61c3c2372a..2f3e6fa931e644 100644 --- a/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_friendly_names.ts +++ b/x-pack/plugins/security_solution/public/management/components/policy_response/policy_response_friendly_names.ts @@ -390,8 +390,13 @@ export const descriptions = Object.freeze( ], [ 'linux_deadlock', - // intentionally blank for now: https://github.com/elastic/security-team/issues/4264#issuecomment-1194136633 - '', + i18n.translate( + 'xpack.securitySolution.endpoint.details.policyResponse.description.linux_deadlock', + { + defaultMessage: + 'Malware protection was disabled to avoid a potential system deadlock. To resolve this issue, the file systems causing this need to be identified in integration policy advanced settings (linux.advanced.fanotify.ignored_filesystems). Learn more in our', + } + ), ], ]) ); @@ -421,7 +426,7 @@ const linkTexts = Object.freeze( i18n.translate( 'xpack.securitySolution.endpoint.details.policyResponse.link.text.linux_deadlock', { - defaultMessage: ' Learn more.', + defaultMessage: ' troubleshooting docs.', } ), ], From 946e09463767c79524ef960cef8ff259a797582f Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 11 Aug 2022 15:56:44 -0400 Subject: [PATCH 31/59] [cft] Add support for creating a new deployment (#138243) * [cft] Add support for creating a new redeployment - Adds a new label `ci:cloud-redeploy` that will always create a fresh deployment - Deprecates `ci:deploy-cloud` in favor of namespacing `ci:cloud-deploy` * booleans --- .../pipelines/pull_request/pipeline.ts | 6 ++- .../scripts/steps/cloud/build_and_deploy.sh | 37 ++++++++++++------- .../scripts/steps/cloud/purge_deployments.ts | 8 +++- dev_docs/tutorials/ci.mdx | 8 +++- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.ts b/.buildkite/scripts/pipelines/pull_request/pipeline.ts index c8062a7f8108ae..59cac2eaf5259a 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.ts +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.ts @@ -122,7 +122,11 @@ const uploadPipeline = (pipelineContent: string | object) => { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/ux_plugin_e2e.yml')); } - if (GITHUB_PR_LABELS.includes('ci:deploy-cloud')) { + if ( + GITHUB_PR_LABELS.includes('ci:deploy-cloud') || + GITHUB_PR_LABELS.includes('ci:cloud-deploy') || + GITHUB_PR_LABELS.includes('ci:cloud-redeploy') + ) { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/deploy_cloud.yml')); } diff --git a/.buildkite/scripts/steps/cloud/build_and_deploy.sh b/.buildkite/scripts/steps/cloud/build_and_deploy.sh index 3717a058e98287..613e11f76252ad 100755 --- a/.buildkite/scripts/steps/cloud/build_and_deploy.sh +++ b/.buildkite/scripts/steps/cloud/build_and_deploy.sh @@ -9,6 +9,7 @@ source .buildkite/scripts/common/util.sh export KBN_NP_PLUGINS_BUILT=true VERSION="$(jq -r '.version' package.json)-SNAPSHOT" +ECCTL_LOGS=$(mktemp --suffix ".json") echo "--- Download Kibana Distribution" @@ -46,9 +47,19 @@ fi docker logout docker.elastic.co +if is_pr_with_label "ci:cloud-redeploy"; then + echo "--- Shutdown Previous Deployment" + CLOUD_DEPLOYMENT_ID=$(ecctl deployment list --output json | jq -r '.deployments[] | select(.name == "'$CLOUD_DEPLOYMENT_NAME'") | .id') + if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then + echo "No deployment to remove" + else + echo -n "Shutting down previous deployment..." + ecctl deployment shutdown "$CLOUD_DEPLOYMENT_ID" --force --track --output json > "$ECCTL_LOGS" + fi +fi + echo "--- Create Deployment" CLOUD_DEPLOYMENT_ID=$(ecctl deployment list --output json | jq -r '.deployments[] | select(.name == "'$CLOUD_DEPLOYMENT_NAME'") | .id') -JSON_FILE=$(mktemp --suffix ".json") if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then jq ' .resources.kibana[0].plan.kibana.docker_image = "'$KIBANA_CLOUD_IMAGE'" | @@ -61,13 +72,13 @@ if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then ' .buildkite/scripts/steps/cloud/deploy.json > /tmp/deploy.json echo -n "Creating deployment..." - ecctl deployment create --track --output json --file /tmp/deploy.json > "$JSON_FILE" + ecctl deployment create --track --output json --file /tmp/deploy.json > "$ECCTL_LOGS" echo "done" - CLOUD_DEPLOYMENT_USERNAME=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.username' "$JSON_FILE") - CLOUD_DEPLOYMENT_PASSWORD=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.password' "$JSON_FILE") - CLOUD_DEPLOYMENT_ID=$(jq -r --slurp '.[0].id' "$JSON_FILE") - CLOUD_DEPLOYMENT_STATUS_MESSAGES=$(jq --slurp '[.[]|select(.resources == null)]' "$JSON_FILE") + CLOUD_DEPLOYMENT_USERNAME=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.username' "$ECCTL_LOGS") + CLOUD_DEPLOYMENT_PASSWORD=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.password' "$ECCTL_LOGS") + CLOUD_DEPLOYMENT_ID=$(jq -r --slurp '.[0].id' "$ECCTL_LOGS") + CLOUD_DEPLOYMENT_STATUS_MESSAGES=$(jq --slurp '[.[]|select(.resources == null)]' "$ECCTL_LOGS") echo -n "Writing to vault..." VAULT_ROLE_ID="$(retry 5 15 gcloud secrets versions access latest --secret=kibana-buildkite-vault-role-id)" @@ -81,23 +92,23 @@ if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then .settings.observability.metrics.destination.deployment_id = "'$CLOUD_DEPLOYMENT_ID'" | .settings.observability.logging.destination.deployment_id = "'$CLOUD_DEPLOYMENT_ID'" ' .buildkite/scripts/steps/cloud/stack_monitoring.json > /tmp/stack_monitoring.json - ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/stack_monitoring.json > "$JSON_FILE" + ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/stack_monitoring.json > "$ECCTL_LOGS" echo "done" echo -n "Enabling verbose logging..." ecctl deployment show "$CLOUD_DEPLOYMENT_ID" --generate-update-payload | jq ' .resources.kibana[0].plan.kibana.user_settings_yaml = "logging.root.level: all" ' > /tmp/verbose_logging.json - ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/verbose_logging.json > "$JSON_FILE" + ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/verbose_logging.json > "$ECCTL_LOGS" echo "done" else -ecctl deployment show "$CLOUD_DEPLOYMENT_ID" --generate-update-payload | jq ' - .resources.kibana[0].plan.kibana.docker_image = "'$KIBANA_CLOUD_IMAGE'" | - (.. | select(.version? != null).version) = "'$VERSION'" - ' > /tmp/deploy.json + ecctl deployment show "$CLOUD_DEPLOYMENT_ID" --generate-update-payload | jq ' + .resources.kibana[0].plan.kibana.docker_image = "'$KIBANA_CLOUD_IMAGE'" | + (.. | select(.version? != null).version) = "'$VERSION'" + ' > /tmp/deploy.json echo -n "Updating deployment..." - ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/deploy.json > "$JSON_FILE" + ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/deploy.json > "$ECCTL_LOGS" echo "done" fi diff --git a/.buildkite/scripts/steps/cloud/purge_deployments.ts b/.buildkite/scripts/steps/cloud/purge_deployments.ts index 8589d776e884ff..127e3df5f75801 100644 --- a/.buildkite/scripts/steps/cloud/purge_deployments.ts +++ b/.buildkite/scripts/steps/cloud/purge_deployments.ts @@ -31,9 +31,13 @@ for (const deployment of prDeployments) { if (pullRequest.state !== 'OPEN') { console.log(`Pull Request #${prNumber} is no longer open, will delete associated deployment`); deploymentsToPurge.push(deployment); - } else if (!pullRequest.labels.filter((label: any) => label.name === 'ci:deploy-cloud')) { + } else if ( + !pullRequest.labels.filter((label: any) => + /^ci:(deploy-cloud|cloud-deploy|cloud-redeploy)$/.test(label.name) + ) + ) { console.log( - `Pull Request #${prNumber} no longer has the ci:deploy-cloud label, will delete associated deployment` + `Pull Request #${prNumber} no longer has the a cloud deployment label, will delete associated deployment` ); deploymentsToPurge.push(deployment); } else if (lastCommitTimestamp < NOW - 60 * 60 * 24 * 7) { diff --git a/dev_docs/tutorials/ci.mdx b/dev_docs/tutorials/ci.mdx index 6598ed9855dc0b..baa9ee588fe713 100644 --- a/dev_docs/tutorials/ci.mdx +++ b/dev_docs/tutorials/ci.mdx @@ -31,9 +31,13 @@ Build documentation from the root `docs` folder. Labels can be added to a pull request to run conditional pipelines. -#### `ci:deploy-cloud` +#### `ci:cloud-deploy` -Deploy a pull request to Elastic Cloud. Deployment information will be available as an annotation at the top of a build. Access credentials will be available in vault. +Create or update a deployment on Elastic Cloud. + +#### `ci:cloud-redeploy` + +Create a new deployment on Elastic Cloud. Previous deployments linked to a pull request will be shutdown and data will not be preserved. #### `ci:build-all-platforms` From 1c59a0996591b9148af59b9c40c33fe5007c4487 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 11 Aug 2022 17:16:17 -0400 Subject: [PATCH 32/59] [cft] Stabilize deployment creation (#136974) After a deployment is created, a new Kibana plan is automatically added to update settings (to connect APM) and restart Kibana. Polling for a plan state isn't especially reliable because it flips between empty and queued, and then empty again depending on how quickly setup is run in cloud. We want to enable monitoring after the automatic plan has run, if not we get an error: * deployments.resource_plan_state_error: Kibana resource [main-kibana] has a plan still pending, cancel that or wait for it to complete (settings.observability.plan) This adds a sleep and retry to see if we can make this step more reliable --- .../scripts/steps/cloud/build_and_deploy.sh | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/.buildkite/scripts/steps/cloud/build_and_deploy.sh b/.buildkite/scripts/steps/cloud/build_and_deploy.sh index 613e11f76252ad..05427de0582251 100755 --- a/.buildkite/scripts/steps/cloud/build_and_deploy.sh +++ b/.buildkite/scripts/steps/cloud/build_and_deploy.sh @@ -53,7 +53,7 @@ if is_pr_with_label "ci:cloud-redeploy"; then if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then echo "No deployment to remove" else - echo -n "Shutting down previous deployment..." + echo "Shutting down previous deployment..." ecctl deployment shutdown "$CLOUD_DEPLOYMENT_ID" --force --track --output json > "$ECCTL_LOGS" fi fi @@ -71,45 +71,49 @@ if [ -z "${CLOUD_DEPLOYMENT_ID}" ]; then .resources.integrations_server[0].plan.integrations_server.version = "'$VERSION'" ' .buildkite/scripts/steps/cloud/deploy.json > /tmp/deploy.json - echo -n "Creating deployment..." + echo "Creating deployment..." ecctl deployment create --track --output json --file /tmp/deploy.json > "$ECCTL_LOGS" - echo "done" CLOUD_DEPLOYMENT_USERNAME=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.username' "$ECCTL_LOGS") CLOUD_DEPLOYMENT_PASSWORD=$(jq --slurp '.[]|select(.resources).resources[] | select(.credentials).credentials.password' "$ECCTL_LOGS") CLOUD_DEPLOYMENT_ID=$(jq -r --slurp '.[0].id' "$ECCTL_LOGS") CLOUD_DEPLOYMENT_STATUS_MESSAGES=$(jq --slurp '[.[]|select(.resources == null)]' "$ECCTL_LOGS") - echo -n "Writing to vault..." + echo "Writing to vault..." VAULT_ROLE_ID="$(retry 5 15 gcloud secrets versions access latest --secret=kibana-buildkite-vault-role-id)" VAULT_SECRET_ID="$(retry 5 15 gcloud secrets versions access latest --secret=kibana-buildkite-vault-secret-id)" VAULT_TOKEN=$(retry 5 30 vault write -field=token auth/approle/login role_id="$VAULT_ROLE_ID" secret_id="$VAULT_SECRET_ID") retry 5 30 vault login -no-print "$VAULT_TOKEN" retry 5 5 vault write "secret/kibana-issues/dev/cloud-deploy/$CLOUD_DEPLOYMENT_NAME" username="$CLOUD_DEPLOYMENT_USERNAME" password="$CLOUD_DEPLOYMENT_PASSWORD" - echo -n "Enabling Stack Monitoring..." + echo "Enabling Stack Monitoring..." jq ' .settings.observability.metrics.destination.deployment_id = "'$CLOUD_DEPLOYMENT_ID'" | .settings.observability.logging.destination.deployment_id = "'$CLOUD_DEPLOYMENT_ID'" ' .buildkite/scripts/steps/cloud/stack_monitoring.json > /tmp/stack_monitoring.json - ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/stack_monitoring.json > "$ECCTL_LOGS" - echo "done" - echo -n "Enabling verbose logging..." + # After a deployment is created, a new Kibana plan is automatically added to update settings + # and restart Kibana. Polling for a plan state isn't especially reliable because it flips + # between empty and queued, and then empty again depending on how quickly setup is run in cloud. + # We want to enable monitoring after the automatic plan has run, if not we get an error: + # * deployments.resource_plan_state_error: Kibana resource [main-kibana] has a plan still pending, cancel that or wait for it to complete (settings.observability.plan) + # This adds a sleep and retry to see if we can make this step more reliable + sleep 120 + retry 5 60 ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/stack_monitoring.json > "$ECCTL_LOGS" + + echo "Enabling verbose logging..." ecctl deployment show "$CLOUD_DEPLOYMENT_ID" --generate-update-payload | jq ' .resources.kibana[0].plan.kibana.user_settings_yaml = "logging.root.level: all" ' > /tmp/verbose_logging.json ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/verbose_logging.json > "$ECCTL_LOGS" - echo "done" else ecctl deployment show "$CLOUD_DEPLOYMENT_ID" --generate-update-payload | jq ' .resources.kibana[0].plan.kibana.docker_image = "'$KIBANA_CLOUD_IMAGE'" | (.. | select(.version? != null).version) = "'$VERSION'" ' > /tmp/deploy.json - echo -n "Updating deployment..." + echo "Updating deployment..." ecctl deployment update "$CLOUD_DEPLOYMENT_ID" --track --output json --file /tmp/deploy.json > "$ECCTL_LOGS" - echo "done" fi CLOUD_DEPLOYMENT_KIBANA_URL=$(ecctl deployment show "$CLOUD_DEPLOYMENT_ID" | jq -r '.resources.kibana[0].info.metadata.aliased_url') From cb0ca889a9c9d1ffa0d752ae7e254aba9c172efc Mon Sep 17 00:00:00 2001 From: Davis Plumlee <56367316+dplumlee@users.noreply.github.com> Date: Thu, 11 Aug 2022 23:19:28 +0200 Subject: [PATCH 33/59] [Security Solution] Adds read only prop to preview table details flyout threat summary (#138665) --- .../cti_details/enrichment_summary.tsx | 9 +++++++-- .../cti_details/threat_summary_view.tsx | 13 ++++++++++++- .../components/event_details/event_details.tsx | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx index b6367e9f7ffeb0..090745707e3c88 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx @@ -33,6 +33,7 @@ export interface ThreatSummaryDescription { timelineId: string; value: string | undefined; isDraggable?: boolean; + isReadOnly?: boolean; } const EnrichmentFieldFeedName = styled.span` @@ -65,6 +66,7 @@ const EnrichmentDescription: React.FC = ({ timelineId, value, isDraggable, + isReadOnly, }) => { if (!data || !value) return null; const key = `alert-details-value-formatted-field-value-${timelineId}-${eventId}-${data.field}-${value}-${index}-${feedName}`; @@ -92,7 +94,7 @@ const EnrichmentDescription: React.FC = ({
    - {value && ( + {value && !isReadOnly && ( = ({ browserFields, data, enrichments, timelineId, eventId, isDraggable }) => { + isReadOnly?: boolean; +}> = ({ browserFields, data, enrichments, timelineId, eventId, isDraggable, isReadOnly }) => { const parsedEnrichments = enrichments.map((enrichment, index) => { const { field, type, feedName, value } = getEnrichmentIdentifiers(enrichment); const eventData = data.find((item) => item.field === field); @@ -168,6 +171,7 @@ const EnrichmentSummaryComponent: React.FC<{ data={fieldsData} browserField={browserField} isDraggable={isDraggable} + isReadOnly={isReadOnly} /> } /> @@ -198,6 +202,7 @@ const EnrichmentSummaryComponent: React.FC<{ data={fieldsData} browserField={browserField} isDraggable={isDraggable} + isReadOnly={isReadOnly} /> } /> diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx index 21648200f3177c..a7a371e60cf9e4 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx @@ -127,7 +127,17 @@ const ThreatSummaryViewComponent: React.FC<{ timelineId: string; hostRisk: HostRisk | null; isDraggable?: boolean; -}> = ({ browserFields, data, enrichments, eventId, timelineId, hostRisk, isDraggable }) => { + isReadOnly?: boolean; +}> = ({ + browserFields, + data, + enrichments, + eventId, + timelineId, + hostRisk, + isDraggable, + isReadOnly, +}) => { if (!hostRisk && enrichments.length === 0) { return null; } @@ -155,6 +165,7 @@ const ThreatSummaryViewComponent: React.FC<{ timelineId={timelineId} eventId={eventId} isDraggable={isDraggable} + isReadOnly={isReadOnly} /> diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx index d94979d7055120..11ca04b1224dea 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx @@ -202,6 +202,7 @@ const EventDetailsComponent: React.FC = ({ eventId={id} timelineId={timelineId} enrichments={allEnrichments} + isReadOnly={isReadOnly} /> )} From af9e2d9569b1c8c6185ae71cbfab7cbbb67a5583 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 11 Aug 2022 17:29:34 -0400 Subject: [PATCH 34/59] [Security Solution][Endpoint] Un-skip Jest tests for artifact list page delete modal (#138672) * Add an `waitFor` before selecting dialog buttons * increase `beforeEach()` timeout to 10s --- .../components/artifact_delete_modal.test.ts | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_delete_modal.test.ts b/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_delete_modal.test.ts index a0baac5b7163c2..497baa999cf2e5 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_delete_modal.test.ts +++ b/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_delete_modal.test.ts @@ -13,8 +13,7 @@ import { act, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { getDeferred } from '../../mocks'; -// FLAKY: https://github.com/elastic/kibana/issues/137590 -describe.skip('When displaying the Delete artfifact modal in the Artifact List Page', () => { +describe('When displaying the Delete artifact modal in the Artifact List Page', () => { let renderResult: ReturnType; let history: AppContextTestRender['history']; let coreStart: AppContextTestRender['coreStart']; @@ -38,30 +37,45 @@ describe.skip('When displaying the Delete artfifact modal in the Artifact List P }); }; - beforeEach(async () => { - const renderSetup = getArtifactListPageRenderingSetup(); + beforeEach( + async () => { + const renderSetup = getArtifactListPageRenderingSetup(); - ({ history, coreStart, mockedApi, getFirstCard } = renderSetup); + ({ history, coreStart, mockedApi, getFirstCard } = renderSetup); - history.push('somepage?show=create'); + history.push('somepage?show=create'); - renderResult = renderSetup.renderArtifactListPage(); + renderResult = renderSetup.renderArtifactListPage(); - await act(async () => { - await waitFor(() => { - expect(renderResult.getByTestId('testPage-list')).toBeTruthy(); + await act(async () => { + await waitFor(() => { + expect(renderResult.getByTestId('testPage-list')).toBeTruthy(); + }); }); - }); - await clickCardAction('delete'); + await clickCardAction('delete'); - cancelButton = renderResult.getByTestId( - 'testPage-deleteModal-cancelButton' - ) as HTMLButtonElement; - submitButton = renderResult.getByTestId( - 'testPage-deleteModal-submitButton' - ) as HTMLButtonElement; - }); + // Wait for the dialog to be present + await act(async () => { + await waitFor(() => { + expect(renderResult.getByTestId('testPage-deleteModal')).not.toBeNull(); + }); + }); + + cancelButton = renderResult.getByTestId( + 'testPage-deleteModal-cancelButton' + ) as HTMLButtonElement; + + submitButton = renderResult.getByTestId( + 'testPage-deleteModal-submitButton' + ) as HTMLButtonElement; + }, + // Timeout set to 10s + // In some cases, whose causes are unknown, a test will timeout and will point + // to this setup as the culprid. It rarely happens, but in order to avoid it, + // the timeout below is being set to 10s + 10000 + ); it('should show Cancel and Delete buttons enabled', async () => { expect(cancelButton).toBeEnabled(); From 288006a12ce1a8b46d72b56e72976ad8551faece Mon Sep 17 00:00:00 2001 From: Or Ouziel Date: Fri, 12 Aug 2022 02:07:57 +0300 Subject: [PATCH 35/59] [Cloud Posture] fix CSP fleet extension form (#138647) --- .../public/components/fleet_extensions/mocks.ts | 4 ++-- .../public/components/fleet_extensions/utils.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts index c2281706d7d22d..4477848bf7ba2e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts @@ -22,7 +22,7 @@ export const getCspNewPolicyMock = (type: BenchmarkId = 'cis_k8s'): NewPackagePo enabled: type === 'cis_k8s', streams: [ { - enabled: true, + enabled: type === 'cis_k8s', data_stream: { type: 'logs', dataset: 'cloud_security_posture.findings', @@ -36,7 +36,7 @@ export const getCspNewPolicyMock = (type: BenchmarkId = 'cis_k8s'): NewPackagePo enabled: type === 'cis_eks', streams: [ { - enabled: false, + enabled: type === 'cis_eks', data_stream: { type: 'logs', dataset: 'cloud_security_posture.findings', diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 618bf6b27498bd..9641606abfcf74 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -20,6 +20,10 @@ export const getUpdatedDeploymentType = (newPolicy: NewPackagePolicy, inputType: inputs: newPolicy.inputs.map((item) => ({ ...item, enabled: item.type === inputType, + streams: item.streams.map((stream) => ({ + ...stream, + enabled: item.type === inputType, + })), })), }, }); From 0715ca18097b1c27aebc03a53eaa4e7ac0838825 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 12 Aug 2022 00:43:50 -0400 Subject: [PATCH 36/59] [api-docs] Daily api_docs build (#138696) --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.devdocs.json | 18 +- api_docs/apm.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/controls.mdx | 2 +- api_docs/core.mdx | 2 +- api_docs/core_application.mdx | 2 +- api_docs/core_chrome.mdx | 2 +- api_docs/core_saved_objects.mdx | 2 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.devdocs.json | 4 +- api_docs/data.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.devdocs.json | 6 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 2 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/elastic_apm_synthtrace.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.devdocs.json | 85 +- api_docs/expression_x_y.mdx | 4 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.devdocs.json | 5622 +++++++++++++++++ api_docs/files.mdx | 55 + api_docs/fleet.devdocs.json | 10 +- api_docs/fleet.mdx | 2 +- api_docs/global_search.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- api_docs/kbn_alerts.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- ..._analytics_shippers_elastic_v3_browser.mdx | 2 +- ...n_analytics_shippers_elastic_v3_common.mdx | 2 +- ...n_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bazel_packages.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- .../kbn_core_injected_metadata_browser.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- .../kbn_core_mount_utils_browser_internal.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_internal.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_doc_links.devdocs.json | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_get_repo_files.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_kibana_manifest_parser.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- ...nce_testing_dataset_extractor.devdocs.json | 4 +- ..._performance_testing_dataset_extractor.mdx | 4 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- ...hared_ux_button_exit_full_screen_mocks.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_components.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_services.mdx | 2 +- api_docs/kbn_shared_ux_storybook.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_package_json.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_type_summarizer.mdx | 2 +- api_docs/kbn_type_summarizer_core.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.devdocs.json | 59 +- api_docs/lens.mdx | 4 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/observability.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/plugin_directory.mdx | 15 +- api_docs/presentation_util.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.devdocs.json | 12 + api_docs/security.mdx | 4 +- api_docs/security_solution.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/shared_u_x.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/threat_intelligence.mdx | 2 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.mdx | 2 +- 356 files changed, 6170 insertions(+), 418 deletions(-) create mode 100644 api_docs/files.devdocs.json create mode 100644 api_docs/files.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index f282d76f832a9f..de4eba6353c6d4 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index d2ceaab33973da..e7aa06d92dfefe 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 187f9343d71c4b..6c4b9688098d38 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index dc6b0afa761ed0..f0814c7dba4e91 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index c0ab6b4b2f6f5c..10eb9c1dc4af54 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -1242,7 +1242,11 @@ "StringC", "; transactionType: ", "StringC", - "; }>, ", + "; durationMin: ", + "Type", + "; durationMax: ", + "Type", + "; }>, ", "TypeC", "<{ environment: ", "UnionC", @@ -1300,7 +1304,11 @@ "StringC", "; transactionType: ", "StringC", - "; }>, ", + "; durationMin: ", + "Type", + "; durationMax: ", + "Type", + "; }>, ", "TypeC", "<{ environment: ", "UnionC", @@ -4918,7 +4926,11 @@ "StringC", ", ", "Type", - "]>; }>>; }>, ", + "]>; }>>; durationMin: ", + "Type", + "; durationMax: ", + "Type", + "; }>, ", "TypeC", "<{ environment: ", "UnionC", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 7300c7c4e6e798..9d4eaee59cf092 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 0b0ed7407957d0..d02c5b9af3daea 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index d69a594d888e18..46cb08f6e7a135 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index e7815d47682eeb..28a7a2b005ed81 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 303a1b51161d52..df0d479e90ffb6 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 2f719228ffca3c..84217951a6902f 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 92fb236da4dfe3..1f4b5549584284 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 3187f3c79b136e..40bf4ffb59c637 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index c8fa214ebb827c..49c753ee586479 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 3bf15c15f0ecf1..c38896700071ad 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 3574957c8e0fc1..ba23f462391e44 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index c3589c46a04696..8fc3fe4b300974 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-application title: "core.application" image: https://source.unsplash.com/400x175/?github description: API docs for the core.application plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.application'] --- import coreApplicationObj from './core_application.devdocs.json'; diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index 7bace2a507a6c5..31baab2ea06d5b 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-chrome title: "core.chrome" image: https://source.unsplash.com/400x175/?github description: API docs for the core.chrome plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.chrome'] --- import coreChromeObj from './core_chrome.devdocs.json'; diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index 6fcd60f4851a4f..981214850022c1 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-savedObjects title: "core.savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the core.savedObjects plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.savedObjects'] --- import coreSavedObjectsObj from './core_saved_objects.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 43bfe0acae3097..8ecf3a62c18973 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index e9b89abcc6115a..a455f42493cf3d 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 9e9e9022ad468b..bc614535a6368f 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 769438a0491019..5c83ebefbb35e9 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -12590,7 +12590,7 @@ "tags": [], "label": "getAllRuntimeFields", "description": [ - "\nGet all runtime field definitions." + "\nGet all runtime field definitions.\nNOTE: this does not strip out runtime fields that match mapped field names" ], "signature": [ "() => Record Record Record Record Record | undefined; mimeType?: string | undefined; }) => Promise<{ file: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.create.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- create file args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [ + "\nDelete a file object and all associated share and content objects.\n" + ], + "signature": [ + "(args: { id: string; }) => Promise<{ ok: true; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.delete.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- delete file args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.getById", + "type": "Function", + "tags": [], + "label": "getById", + "description": [ + "\nGet a file object by ID.\n" + ], + "signature": [ + "(args: { id: string; }) => Promise<{ file: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.getById.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- get file by ID args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.list", + "type": "Function", + "tags": [], + "label": "list", + "description": [ + "\nList all file objects, of a given {@link FileKind}.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + }, + ") => Promise<{ files: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "[]; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.list.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- list files args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nUpdate a set of of metadata values of the file object.\n" + ], + "signature": [ + "(args: { name?: string | undefined; alt?: string | undefined; meta?: Record | undefined; } & { id: string; }) => Promise<{ file: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.update.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- update file args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.upload", + "type": "Function", + "tags": [], + "label": "upload", + "description": [ + "\nStream the contents of the file to Kibana server for storage.\n" + ], + "signature": [ + "(args: any) => Promise<{ ok: true; size: number; }>" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.upload.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- upload file args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClient.download", + "type": "Function", + "tags": [], + "label": "download", + "description": [ + "\nStream a download of the file object's content.\n" + ], + "signature": [ + "(args: { id: string; fileName?: string | undefined; }) => Promise" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClient.download.$1", + "type": "CompoundType", + "tags": [], + "label": "args", + "description": [ + "- download file args" + ], + "signature": [ + "E[\"inputs\"][\"body\"] & E[\"inputs\"][\"params\"] & E[\"inputs\"][\"query\"]" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false + } + ] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-public.FilesClientFactory", + "type": "Interface", + "tags": [], + "label": "FilesClientFactory", + "description": [ + "\nA factory for creating a {@link FilesClient}" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClientFactory.asScoped", + "type": "Function", + "tags": [], + "label": "asScoped", + "description": [ + "\nCreate a {@link FileClient} for a given {@link FileKind}.\n" + ], + "signature": [ + "(fileKind: string) => ", + { + "pluginId": "files", + "scope": "public", + "docId": "kibFilesPluginApi", + "section": "def-public.FilesClient", + "text": "FilesClient" + } + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-public.FilesClientFactory.asScoped.$1", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "- The {@link FileKind } to create a client for." + ], + "signature": [ + "string" + ], + "path": "x-pack/plugins/files/public/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "files", + "id": "def-server.createEsFileClient", + "type": "Function", + "tags": [ + "note" + ], + "label": "createEsFileClient", + "description": [ + "\nA utility function for creating an instance of {@link FileClient}\nthat will speak with ES indices only for file functionality.\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.CreateEsFileClientArgs", + "text": "CreateEsFileClientArgs" + }, + ") => ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileClient", + "text": "FileClient" + } + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.createEsFileClient.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- See {@link CreateEsFileClientArgs }" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.CreateEsFileClientArgs", + "text": "CreateEsFileClientArgs" + } + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs", + "type": "Interface", + "tags": [], + "label": "CreateEsFileClientArgs", + "description": [ + "\nArguments to create an ES file client." + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs.metadataIndex", + "type": "string", + "tags": [], + "label": "metadataIndex", + "description": [ + "\nThe name of the ES index that will store file metadata." + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs.blobStorageIndex", + "type": "string", + "tags": [], + "label": "blobStorageIndex", + "description": [ + "\nThe name of the ES index that will store file contents." + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs.elasticsearchClient", + "type": "Object", + "tags": [], + "label": "elasticsearchClient", + "description": [ + "\nAn elasticsearch client that will be used to interact with the cluster" + ], + "signature": [ + "{ name: string | symbol; transform: ", + "default", + "; search: { >(this: That, params?: ", + "SearchRequest", + " | ", + "SearchRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "SearchResponse", + ">; >(this: That, params?: ", + "SearchRequest", + " | ", + "SearchRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "SearchResponse", + ", unknown>>; >(this: That, params?: ", + "SearchRequest", + " | ", + "SearchRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "SearchResponse", + ">; }; cluster: ", + "default", + "; eql: ", + "default", + "; create: { (this: That, params: ", + "CreateRequest", + " | ", + "CreateRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "WriteResponseBase", + ">; (this: That, params: ", + "CreateRequest", + " | ", + "CreateRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "WriteResponseBase", + ", unknown>>; (this: That, params: ", + "CreateRequest", + " | ", + "CreateRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "WriteResponseBase", + ">; }; monitoring: ", + "default", + "; security: ", + "default", + "; index: { (this: That, params: ", + "IndexRequest", + " | ", + "IndexRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "WriteResponseBase", + ">; (this: That, params: ", + "IndexRequest", + " | ", + "IndexRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "WriteResponseBase", + ", unknown>>; (this: That, params: ", + "IndexRequest", + " | ", + "IndexRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "WriteResponseBase", + ">; }; get: { (this: That, params: ", + "GetRequest", + " | ", + "GetRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "GetResponse", + ">; (this: That, params: ", + "GetRequest", + " | ", + "GetRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "GetResponse", + ", unknown>>; (this: That, params: ", + "GetRequest", + " | ", + "GetRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "GetResponse", + ">; }; update: { (this: That, params: ", + "UpdateRequest", + " | ", + "UpdateRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "UpdateResponse", + ">; (this: That, params: ", + "UpdateRequest", + " | ", + "UpdateRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "UpdateResponse", + ", unknown>>; (this: That, params: ", + "UpdateRequest", + " | ", + "UpdateRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "UpdateResponse", + ">; }; delete: { (this: That, params: ", + "DeleteRequest", + " | ", + "DeleteRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "WriteResponseBase", + ">; (this: That, params: ", + "DeleteRequest", + " | ", + "DeleteRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "WriteResponseBase", + ", unknown>>; (this: That, params: ", + "DeleteRequest", + " | ", + "DeleteRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "WriteResponseBase", + ">; }; [kInternal]: symbol | null; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kRollup]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + "default", + "; helpers: ", + "default", + "; child: (opts: ", + "ClientOptions", + ") => ", + "default", + "; Internal: ", + "default", + "; asyncSearch: ", + "default", + "; autoscaling: ", + "default", + "; bulk: { (this: That, params: ", + "BulkRequest", + " | ", + "BulkRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "BulkResponse", + ">; (this: That, params: ", + "BulkRequest", + " | ", + "BulkRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "BulkResponse", + ", unknown>>; (this: That, params: ", + "BulkRequest", + " | ", + "BulkRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "BulkResponse", + ">; }; cat: ", + "default", + "; ccr: ", + "default", + "; clearScroll: { (this: That, params?: ", + "ClearScrollRequest", + " | ", + "ClearScrollRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ClearScrollResponse", + ">; (this: That, params?: ", + "ClearScrollRequest", + " | ", + "ClearScrollRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ClearScrollResponse", + ", unknown>>; (this: That, params?: ", + "ClearScrollRequest", + " | ", + "ClearScrollRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ClearScrollResponse", + ">; }; closePointInTime: { (this: That, params: ", + "ClosePointInTimeRequest", + " | ", + "ClosePointInTimeRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ClosePointInTimeResponse", + ">; (this: That, params: ", + "ClosePointInTimeRequest", + " | ", + "ClosePointInTimeRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ClosePointInTimeResponse", + ", unknown>>; (this: That, params: ", + "ClosePointInTimeRequest", + " | ", + "ClosePointInTimeRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ClosePointInTimeResponse", + ">; }; count: { (this: That, params?: ", + "CountRequest", + " | ", + "CountRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "CountResponse", + ">; (this: That, params?: ", + "CountRequest", + " | ", + "CountRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "CountResponse", + ", unknown>>; (this: That, params?: ", + "CountRequest", + " | ", + "CountRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "CountResponse", + ">; }; danglingIndices: ", + "default", + "; deleteByQuery: { (this: That, params: ", + "DeleteByQueryRequest", + " | ", + "DeleteByQueryRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "DeleteByQueryResponse", + ">; (this: That, params: ", + "DeleteByQueryRequest", + " | ", + "DeleteByQueryRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "DeleteByQueryResponse", + ", unknown>>; (this: That, params: ", + "DeleteByQueryRequest", + " | ", + "DeleteByQueryRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "DeleteByQueryResponse", + ">; }; deleteByQueryRethrottle: { (this: That, params: ", + "DeleteByQueryRethrottleRequest", + " | ", + "DeleteByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TasksTaskListResponseBase", + ">; (this: That, params: ", + "DeleteByQueryRethrottleRequest", + " | ", + "DeleteByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TasksTaskListResponseBase", + ", unknown>>; (this: That, params: ", + "DeleteByQueryRethrottleRequest", + " | ", + "DeleteByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TasksTaskListResponseBase", + ">; }; deleteScript: { (this: That, params: ", + "DeleteScriptRequest", + " | ", + "DeleteScriptRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "AcknowledgedResponseBase", + ">; (this: That, params: ", + "DeleteScriptRequest", + " | ", + "DeleteScriptRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "AcknowledgedResponseBase", + ", unknown>>; (this: That, params: ", + "DeleteScriptRequest", + " | ", + "DeleteScriptRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "AcknowledgedResponseBase", + ">; }; enrich: ", + "default", + "; exists: { (this: That, params: ", + "ExistsRequest", + " | ", + "ExistsRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise; (this: That, params: ", + "ExistsRequest", + " | ", + "ExistsRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + ">; (this: That, params: ", + "ExistsRequest", + " | ", + "ExistsRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise; }; existsSource: { (this: That, params: ", + "ExistsSourceRequest", + " | ", + "ExistsSourceRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise; (this: That, params: ", + "ExistsSourceRequest", + " | ", + "ExistsSourceRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + ">; (this: That, params: ", + "ExistsSourceRequest", + " | ", + "ExistsSourceRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise; }; explain: { (this: That, params: ", + "ExplainRequest", + " | ", + "ExplainRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ExplainResponse", + ">; (this: That, params: ", + "ExplainRequest", + " | ", + "ExplainRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ExplainResponse", + ", unknown>>; (this: That, params: ", + "ExplainRequest", + " | ", + "ExplainRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ExplainResponse", + ">; }; features: ", + "default", + "; fieldCaps: { (this: That, params: ", + "FieldCapsRequest", + " | ", + "FieldCapsRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "FieldCapsResponse", + ">; (this: That, params: ", + "FieldCapsRequest", + " | ", + "FieldCapsRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "FieldCapsResponse", + ", unknown>>; (this: That, params: ", + "FieldCapsRequest", + " | ", + "FieldCapsRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "FieldCapsResponse", + ">; }; fleet: ", + "default", + "; getScript: { (this: That, params: ", + "GetScriptRequest", + " | ", + "GetScriptRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "GetScriptResponse", + ">; (this: That, params: ", + "GetScriptRequest", + " | ", + "GetScriptRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "GetScriptResponse", + ", unknown>>; (this: That, params: ", + "GetScriptRequest", + " | ", + "GetScriptRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "GetScriptResponse", + ">; }; getScriptContext: { (this: That, params?: ", + "GetScriptContextRequest", + " | ", + "GetScriptContextRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "GetScriptContextResponse", + ">; (this: That, params?: ", + "GetScriptContextRequest", + " | ", + "GetScriptContextRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "GetScriptContextResponse", + ", unknown>>; (this: That, params?: ", + "GetScriptContextRequest", + " | ", + "GetScriptContextRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "GetScriptContextResponse", + ">; }; getScriptLanguages: { (this: That, params?: ", + "GetScriptLanguagesRequest", + " | ", + "GetScriptLanguagesRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "GetScriptLanguagesResponse", + ">; (this: That, params?: ", + "GetScriptLanguagesRequest", + " | ", + "GetScriptLanguagesRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "GetScriptLanguagesResponse", + ", unknown>>; (this: That, params?: ", + "GetScriptLanguagesRequest", + " | ", + "GetScriptLanguagesRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "GetScriptLanguagesResponse", + ">; }; getSource: { (this: That, params: ", + "GetSourceRequest", + " | ", + "GetSourceRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise; (this: That, params: ", + "GetSourceRequest", + " | ", + "GetSourceRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + ">; (this: That, params: ", + "GetSourceRequest", + " | ", + "GetSourceRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise; }; graph: ", + "default", + "; ilm: ", + "default", + "; indices: ", + "default", + "; info: { (this: That, params?: ", + "InfoRequest", + " | ", + "InfoRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "InfoResponse", + ">; (this: That, params?: ", + "InfoRequest", + " | ", + "InfoRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "InfoResponse", + ", unknown>>; (this: That, params?: ", + "InfoRequest", + " | ", + "InfoRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "InfoResponse", + ">; }; ingest: ", + "default", + "; knnSearch: { (this: That, params: ", + "KnnSearchRequest", + " | ", + "KnnSearchRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "KnnSearchResponse", + ">; (this: That, params: ", + "KnnSearchRequest", + " | ", + "KnnSearchRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "KnnSearchResponse", + ", unknown>>; (this: That, params: ", + "KnnSearchRequest", + " | ", + "KnnSearchRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "KnnSearchResponse", + ">; }; license: ", + "default", + "; logstash: ", + "default", + "; mget: { (this: That, params?: ", + "MgetRequest", + " | ", + "MgetRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "MgetResponse", + ">; (this: That, params?: ", + "MgetRequest", + " | ", + "MgetRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "MgetResponse", + ", unknown>>; (this: That, params?: ", + "MgetRequest", + " | ", + "MgetRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "MgetResponse", + ">; }; migration: ", + "default", + "; ml: ", + "default", + "; msearch: { >(this: That, params: ", + "MsearchRequest", + " | ", + "MsearchRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "MsearchResponse", + ">; >(this: That, params: ", + "MsearchRequest", + " | ", + "MsearchRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "MsearchResponse", + ", unknown>>; >(this: That, params: ", + "MsearchRequest", + " | ", + "MsearchRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "MsearchResponse", + ">; }; msearchTemplate: { >(this: That, params: ", + "MsearchTemplateRequest", + " | ", + "MsearchTemplateRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "MsearchTemplateResponse", + ">; >(this: That, params: ", + "MsearchTemplateRequest", + " | ", + "MsearchTemplateRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "MsearchTemplateResponse", + ", unknown>>; >(this: That, params: ", + "MsearchTemplateRequest", + " | ", + "MsearchTemplateRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "MsearchTemplateResponse", + ">; }; mtermvectors: { (this: That, params?: ", + "MtermvectorsRequest", + " | ", + "MtermvectorsRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "MtermvectorsResponse", + ">; (this: That, params?: ", + "MtermvectorsRequest", + " | ", + "MtermvectorsRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "MtermvectorsResponse", + ", unknown>>; (this: That, params?: ", + "MtermvectorsRequest", + " | ", + "MtermvectorsRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "MtermvectorsResponse", + ">; }; nodes: ", + "default", + "; openPointInTime: { (this: That, params: ", + "OpenPointInTimeRequest", + " | ", + "OpenPointInTimeRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "OpenPointInTimeResponse", + ">; (this: That, params: ", + "OpenPointInTimeRequest", + " | ", + "OpenPointInTimeRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "OpenPointInTimeResponse", + ", unknown>>; (this: That, params: ", + "OpenPointInTimeRequest", + " | ", + "OpenPointInTimeRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "OpenPointInTimeResponse", + ">; }; ping: { (this: That, params?: ", + "PingRequest", + " | ", + "PingRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise; (this: That, params?: ", + "PingRequest", + " | ", + "PingRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + ">; (this: That, params?: ", + "PingRequest", + " | ", + "PingRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise; }; putScript: { (this: That, params: ", + "PutScriptRequest", + " | ", + "PutScriptRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "AcknowledgedResponseBase", + ">; (this: That, params: ", + "PutScriptRequest", + " | ", + "PutScriptRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "AcknowledgedResponseBase", + ", unknown>>; (this: That, params: ", + "PutScriptRequest", + " | ", + "PutScriptRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "AcknowledgedResponseBase", + ">; }; rankEval: { (this: That, params: ", + "RankEvalRequest", + " | ", + "RankEvalRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "RankEvalResponse", + ">; (this: That, params: ", + "RankEvalRequest", + " | ", + "RankEvalRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "RankEvalResponse", + ", unknown>>; (this: That, params: ", + "RankEvalRequest", + " | ", + "RankEvalRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "RankEvalResponse", + ">; }; reindex: { (this: That, params: ", + "ReindexRequest", + " | ", + "ReindexRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ReindexResponse", + ">; (this: That, params: ", + "ReindexRequest", + " | ", + "ReindexRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ReindexResponse", + ", unknown>>; (this: That, params: ", + "ReindexRequest", + " | ", + "ReindexRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ReindexResponse", + ">; }; reindexRethrottle: { (this: That, params: ", + "ReindexRethrottleRequest", + " | ", + "ReindexRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ReindexRethrottleResponse", + ">; (this: That, params: ", + "ReindexRethrottleRequest", + " | ", + "ReindexRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ReindexRethrottleResponse", + ", unknown>>; (this: That, params: ", + "ReindexRethrottleRequest", + " | ", + "ReindexRethrottleRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ReindexRethrottleResponse", + ">; }; renderSearchTemplate: { (this: That, params?: ", + "RenderSearchTemplateRequest", + " | ", + "RenderSearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "RenderSearchTemplateResponse", + ">; (this: That, params?: ", + "RenderSearchTemplateRequest", + " | ", + "RenderSearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "RenderSearchTemplateResponse", + ", unknown>>; (this: That, params?: ", + "RenderSearchTemplateRequest", + " | ", + "RenderSearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "RenderSearchTemplateResponse", + ">; }; rollup: ", + "default", + "; scriptsPainlessExecute: { (this: That, params?: ", + "ScriptsPainlessExecuteRequest", + " | ", + "ScriptsPainlessExecuteRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ScriptsPainlessExecuteResponse", + ">; (this: That, params?: ", + "ScriptsPainlessExecuteRequest", + " | ", + "ScriptsPainlessExecuteRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ScriptsPainlessExecuteResponse", + ", unknown>>; (this: That, params?: ", + "ScriptsPainlessExecuteRequest", + " | ", + "ScriptsPainlessExecuteRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ScriptsPainlessExecuteResponse", + ">; }; scroll: { >(this: That, params: ", + "ScrollRequest", + " | ", + "ScrollRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "ScrollResponse", + ">; >(this: That, params: ", + "ScrollRequest", + " | ", + "ScrollRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "ScrollResponse", + ", unknown>>; >(this: That, params: ", + "ScrollRequest", + " | ", + "ScrollRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "ScrollResponse", + ">; }; searchMvt: { (this: That, params: ", + "SearchMvtRequest", + " | ", + "SearchMvtRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise; (this: That, params: ", + "SearchMvtRequest", + " | ", + "SearchMvtRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + ">; (this: That, params: ", + "SearchMvtRequest", + " | ", + "SearchMvtRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise; }; searchShards: { (this: That, params?: ", + "SearchShardsRequest", + " | ", + "SearchShardsRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "SearchShardsResponse", + ">; (this: That, params?: ", + "SearchShardsRequest", + " | ", + "SearchShardsRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "SearchShardsResponse", + ", unknown>>; (this: That, params?: ", + "SearchShardsRequest", + " | ", + "SearchShardsRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "SearchShardsResponse", + ">; }; searchTemplate: { (this: That, params?: ", + "SearchTemplateRequest", + " | ", + "SearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "SearchTemplateResponse", + ">; (this: That, params?: ", + "SearchTemplateRequest", + " | ", + "SearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "SearchTemplateResponse", + ", unknown>>; (this: That, params?: ", + "SearchTemplateRequest", + " | ", + "SearchTemplateRequest", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "SearchTemplateResponse", + ">; }; searchableSnapshots: ", + "default", + "; shutdown: ", + "default", + "; slm: ", + "default", + "; snapshot: ", + "default", + "; sql: ", + "default", + "; ssl: ", + "default", + "; tasks: ", + "default", + "; termsEnum: { (this: That, params: ", + "TermsEnumRequest", + " | ", + "TermsEnumRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TermsEnumResponse", + ">; (this: That, params: ", + "TermsEnumRequest", + " | ", + "TermsEnumRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TermsEnumResponse", + ", unknown>>; (this: That, params: ", + "TermsEnumRequest", + " | ", + "TermsEnumRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TermsEnumResponse", + ">; }; termvectors: { (this: That, params: ", + "TermvectorsRequest", + " | ", + "TermvectorsRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TermvectorsResponse", + ">; (this: That, params: ", + "TermvectorsRequest", + " | ", + "TermvectorsRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TermvectorsResponse", + ", unknown>>; (this: That, params: ", + "TermvectorsRequest", + " | ", + "TermvectorsRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TermvectorsResponse", + ">; }; textStructure: ", + "default", + "; updateByQuery: { (this: That, params: ", + "UpdateByQueryRequest", + " | ", + "UpdateByQueryRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "UpdateByQueryResponse", + ">; (this: That, params: ", + "UpdateByQueryRequest", + " | ", + "UpdateByQueryRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "UpdateByQueryResponse", + ", unknown>>; (this: That, params: ", + "UpdateByQueryRequest", + " | ", + "UpdateByQueryRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "UpdateByQueryResponse", + ">; }; updateByQueryRethrottle: { (this: That, params: ", + "UpdateByQueryRethrottleRequest", + " | ", + "UpdateByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "UpdateByQueryRethrottleResponse", + ">; (this: That, params: ", + "UpdateByQueryRethrottleRequest", + " | ", + "UpdateByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "UpdateByQueryRethrottleResponse", + ", unknown>>; (this: That, params: ", + "UpdateByQueryRethrottleRequest", + " | ", + "UpdateByQueryRethrottleRequest", + ", options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "UpdateByQueryRethrottleResponse", + ">; }; watcher: ", + "default", + "; xpack: ", + "default", + "; }" + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs.maxSizeBytes", + "type": "number", + "tags": [], + "label": "maxSizeBytes", + "description": [ + "\nThe maximum file size to be write" + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateEsFileClientArgs.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [ + "\nA logger for debuggin purposes" + ], + "signature": [ + "Logger" + ], + "path": "x-pack/plugins/files/server/file_client/create_es_file_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs", + "type": "Interface", + "tags": [], + "label": "CreateFileArgs", + "description": [ + "\nArguments to create a new file." + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.CreateFileArgs", + "text": "CreateFileArgs" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nFile name" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nFile kind, must correspond to a registered {@link FileKind}." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs.alt", + "type": "string", + "tags": [], + "label": "alt", + "description": [ + "\nAlternate text for accessibility and display purposes." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs.meta", + "type": "Uncategorized", + "tags": [], + "label": "meta", + "description": [ + "\nCustom metadata like tags or identifiers for the file." + ], + "signature": [ + "Meta | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateFileArgs.mime", + "type": "string", + "tags": [], + "label": "mime", + "description": [ + "\nThe MIME type of the file." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateShareArgs", + "type": "Interface", + "tags": [], + "label": "CreateShareArgs", + "description": [ + "\nArguments for a creating a file share" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.CreateShareArgs.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nOptionally provide a name for this file share instance" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateShareArgs.validUntil", + "type": "number", + "tags": [ + "note" + ], + "label": "validUntil", + "description": [ + "\nOptionally set an expiration date as unix timestamp for this file share instance\n" + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.CreateShareArgs.file", + "type": "Object", + "tags": [], + "label": "file", + "description": [ + "\nThe file object to create the share for" + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.DeleteArg", + "type": "Interface", + "tags": [], + "label": "DeleteArg", + "description": [], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.DeleteArg.id", + "type": "string", + "tags": [ + "note" + ], + "label": "id", + "description": [ + "\nUnique ID of file metadata to delete\n" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.DeleteFileArgs", + "type": "Interface", + "tags": [], + "label": "DeleteFileArgs", + "description": [ + "\nArguments to delete a file." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.DeleteFileArgs.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nFile ID." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.DeleteFileArgs.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nFile kind, must correspond to a registered {@link FileKind}." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.DeleteForFileArgs", + "type": "Interface", + "tags": [], + "label": "DeleteForFileArgs", + "description": [ + "\nDelete file shares for file arguments." + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.DeleteForFileArgs.file", + "type": "Object", + "tags": [], + "label": "file", + "description": [ + "\nThe file object to delete the shares for." + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient", + "type": "Interface", + "tags": [], + "label": "FileClient", + "description": [ + "\nWraps the {@link FileMetadataClient} and {@link BlobStorageClient} client\nto provide basic file CRUD functionality.\n\nFor now this is just a shallow type of the implementation for export purposes." + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "See {@link FileMetadata.FileKind}." + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [ + "\nSee {@link FileMetadataClient.create}.\n" + ], + "signature": [ + "(arg: ", + "CreateArgs", + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.create.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Arg to create a file." + ], + "signature": [ + "CreateArgs" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [ + "\nSee {@link FileMetadataClient.get}\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetArg", + "text": "GetArg" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.get.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to get a file" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetArg", + "text": "GetArg" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\n{@link FileMetadataClient.update}\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.update.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to get a file" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [ + "\nDelete a file." + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteArgs", + "text": "DeleteArgs" + }, + ") => Promise" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.delete.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to delete a file" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteArgs", + "text": "DeleteArgs" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.deleteContent", + "type": "Function", + "tags": [], + "label": "deleteContent", + "description": [ + "\nSee {@link BlobStorageClient.delete}\n" + ], + "signature": [ + "(id: string) => Promise" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.deleteContent.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "- Argument to delete a file" + ], + "path": "x-pack/plugins/files/server/blob_storage_service/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.list", + "type": "Function", + "tags": [], + "label": "list", + "description": [ + "\nSee {@link FileMetadataClient.list}\n" + ], + "signature": [ + "(arg?: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArg", + "text": "ListArg" + }, + " | undefined) => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.list.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to list files" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArg", + "text": "ListArg" + }, + " | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [ + "\nSee {@link FileMetadataClient.find}.\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.find.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to find files" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.upload", + "type": "Function", + "tags": [], + "label": "upload", + "description": [ + "\nSee {@link BlobStorageClient.upload}\n" + ], + "signature": [ + "(id: string, rs: ", + "Readable", + ", opts?: ", + "UploadOptions", + " | undefined) => Promise<{ id: string; size: number; }>" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.upload.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "- Readable stream to upload" + ], + "signature": [ + "string" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.upload.$2", + "type": "Object", + "tags": [], + "label": "rs", + "description": [ + "- Readable stream to upload" + ], + "signature": [ + "Readable" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.upload.$3", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "- Argument for uploads" + ], + "signature": [ + "UploadOptions", + " | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileClient.download", + "type": "Function", + "tags": [], + "label": "download", + "description": [ + "\nSee {@link BlobStorageClient.download}\n" + ], + "signature": [ + "(args: { id: string; size?: number | undefined; }) => Promise<", + "Readable", + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_client.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileClient.download.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- to download a file" + ], + "signature": [ + "{ id: string; size?: number | undefined; }" + ], + "path": "x-pack/plugins/files/server/blob_storage_service/types.ts", + "deprecated": false + } + ] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileDescriptor", + "type": "Interface", + "tags": [], + "label": "FileDescriptor", + "description": [ + "\nMeta description of a file." + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileDescriptor.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique ID of a file, used to locate a file." + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileDescriptor.metadata", + "type": "CompoundType", + "tags": [], + "label": "metadata", + "description": [ + "\nThe file's metadata." + ], + "signature": [ + "Required> & ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.BaseFileMetadata", + "text": "BaseFileMetadata" + }, + " & { FileKind: string; Meta?: M | undefined; }" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient", + "type": "Interface", + "tags": [], + "label": "FileMetadataClient", + "description": [ + "\nAn abstraction of storage implementation of file object's (i.e., metadata)" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [ + "\nCreate an instance of file metadata\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.create.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Provide an ID and metadata" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [ + "\nGet file metadata\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetArg", + "text": "GetArg" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.get.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Arguments to retrieve file metadata" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetArg", + "text": "GetArg" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nThe file metadata to update\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.update.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Arguments to update file metadata" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [ + "\nDelete an instance of file metadata\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteArg", + "text": "DeleteArg" + }, + ") => Promise" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.delete.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Arguments to delete file metadata" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteArg", + "text": "DeleteArg" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.list", + "type": "Function", + "tags": [], + "label": "list", + "description": [ + "\nList all instances of metadata for a file kind.\n" + ], + "signature": [ + "(arg?: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArg", + "text": "ListArg" + }, + " | undefined) => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.list.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Arguments to list file metadata" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArg", + "text": "ListArg" + }, + " | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [ + "\nSearch for a set of file kind instances that match the filters.\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileDescriptor", + "text": "FileDescriptor" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.find.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Filters and other settings to match against" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.getUsageMetrics", + "type": "Function", + "tags": [], + "label": "getUsageMetrics", + "description": [ + "\nPrepare a set of metrics based on the file metadata.\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetUsageMetricsArgs", + "text": "GetUsageMetricsArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FilesMetrics", + "text": "FilesMetrics" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileMetadataClient.getUsageMetrics.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- Argument to get usage metrics" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetUsageMetricsArgs", + "text": "GetUsageMetricsArgs" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceFactory", + "type": "Interface", + "tags": [], + "label": "FileServiceFactory", + "description": [ + "\nA simple interface for getting an instance of {@link FileServiceStart}" + ], + "path": "x-pack/plugins/files/server/file_service/file_service_factory.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceFactory.asScoped", + "type": "Function", + "tags": [], + "label": "asScoped", + "description": [ + "\nGet a file service instance that is scoped to the current user request.\n" + ], + "signature": [ + "(req: ", + "KibanaRequest", + ") => ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileServiceStart", + "text": "FileServiceStart" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service_factory.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceFactory.asScoped.$1", + "type": "Object", + "tags": [], + "label": "req", + "description": [ + "- the Kibana request to scope the service to" + ], + "signature": [ + "KibanaRequest", + "" + ], + "path": "x-pack/plugins/files/server/file_service/file_service_factory.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceFactory.asInternal", + "type": "Function", + "tags": [ + "note" + ], + "label": "asInternal", + "description": [ + "\nGet a file service instance that is scoped to the internal user.\n" + ], + "signature": [ + "() => ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileServiceStart", + "text": "FileServiceStart" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service_factory.ts", + "deprecated": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart", + "type": "Interface", + "tags": [], + "label": "FileServiceStart", + "description": [ + "\nPublic file service interface." + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [ + "\nCreate a new file.\n\nOnce created, the file content can be uploaded. See {@link File}.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.CreateFileArgs", + "text": "CreateFileArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.create.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- create file arg" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.CreateFileArgs", + "text": "CreateFileArgs" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nUpdate updatable file attributes like name and meta.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateFileArgs", + "text": "UpdateFileArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.update.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- update file args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateFileArgs", + "text": "UpdateFileArgs" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [ + "\nDelete a file.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteFileArgs", + "text": "DeleteFileArgs" + }, + ") => Promise" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.delete.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- delete file args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.DeleteFileArgs", + "text": "DeleteFileArgs" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getById", + "type": "Function", + "tags": [], + "label": "getById", + "description": [ + "\nGet a file by ID. Will throw if file cannot be found.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetByIdArgs", + "text": "GetByIdArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getById.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- get file by ID args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.GetByIdArgs", + "text": "GetByIdArgs" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.find", + "type": "Function", + "tags": [], + "label": "find", + "description": [ + "\nFind files given a set of parameters.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.find.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- find files args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.list", + "type": "Function", + "tags": [], + "label": "list", + "description": [ + "\nList all files of specific file kind.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListFilesArgs", + "text": "ListFilesArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + "[]>" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.list.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- list files args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListFilesArgs", + "text": "ListFilesArgs" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getShareObject", + "type": "Function", + "tags": [], + "label": "getShareObject", + "description": [ + "\nGet an instance of a share object\n" + ], + "signature": [ + "(arg: IdArg) => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getShareObject.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- get share args" + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.listShareObjects", + "type": "Function", + "tags": [], + "label": "listShareObjects", + "description": [ + "\nList share objects\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArgs", + "text": "ListArgs" + }, + ") => Promise<{ shares: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + "[]; }>" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.listShareObjects.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- list share objects args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArgs", + "text": "ListArgs" + } + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.updateShareObject", + "type": "Function", + "tags": [], + "label": "updateShareObject", + "description": [ + "\nUpdate an instance of a share object\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShare", + "text": "FileShare" + }, + " & { id: string; }>" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.updateShareObject.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- update share args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + } + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.deleteShareObject", + "type": "Function", + "tags": [], + "label": "deleteShareObject", + "description": [ + "\nDelete a share instance\n" + ], + "signature": [ + "(args: IdArg) => Promise" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.deleteShareObject.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- delete share args" + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getUsageMetrics", + "type": "Function", + "tags": [], + "label": "getUsageMetrics", + "description": [ + "\nGet the current usage metrics for all storage media.\n\nReturns diagnostics or `undefined` if metrics could not be retrieved." + ], + "signature": [ + "() => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FilesMetrics", + "text": "FilesMetrics" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getByToken", + "type": "Function", + "tags": [], + "label": "getByToken", + "description": [ + "\nGet a file by a secret token.\n" + ], + "signature": [ + "(token: string) => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileServiceStart.getByToken.$1", + "type": "string", + "tags": [], + "label": "token", + "description": [ + "- secret token" + ], + "signature": [ + "string" + ], + "path": "x-pack/plugins/files/server/file_service/file_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart", + "type": "Interface", + "tags": [], + "label": "FileShareServiceStart", + "description": [ + "\nWe only expose functionality here that do not require you to have a {@link File}\ninstance loaded." + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [ + "\nGet a share instance\n" + ], + "signature": [ + "(arg: IdArg) => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + ">" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.get.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- the arguments to get the share instance" + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.list", + "type": "Function", + "tags": [], + "label": "list", + "description": [ + "\nList share objects\n" + ], + "signature": [ + "(arg: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArgs", + "text": "ListArgs" + }, + ") => Promise<{ shares: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + "[]; }>" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.list.$1", + "type": "Object", + "tags": [], + "label": "arg", + "description": [ + "- the arguments to list share objects" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArgs", + "text": "ListArgs" + } + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nUpdate a share instance.\n" + ], + "signature": [ + "(args: ", + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + ") => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShare", + "text": "FileShare" + }, + " & { id: string; }>" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.update.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- the arguments to update a share instance" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + } + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [ + "\nDelete a share instance.\n" + ], + "signature": [ + "(args: IdArg) => Promise" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FileShareServiceStart.delete.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [ + "- the arguments to delete a share instance" + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindArg", + "type": "Interface", + "tags": [], + "label": "FindArg", + "description": [], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindArg", + "text": "FindArg" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FindArg.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nThe file kind to scope this query to" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs", + "type": "Interface", + "tags": [ + "note" + ], + "label": "FindFileArgs", + "description": [ + "\nArguments to filter for files.\n" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FindFileArgs", + "text": "FindFileArgs" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs.kind", + "type": "Array", + "tags": [], + "label": "kind", + "description": [ + "\nFile kind(s), see {@link FileKind}." + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs.name", + "type": "Array", + "tags": [], + "label": "name", + "description": [ + "\nFile name(s)." + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs.extension", + "type": "Array", + "tags": [], + "label": "extension", + "description": [ + "\nFile extension(s)." + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs.status", + "type": "Array", + "tags": [], + "label": "status", + "description": [ + "\nFile status(es)." + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.FindFileArgs.meta", + "type": "Object", + "tags": [], + "label": "meta", + "description": [ + "\nFile metadata values. These values are governed by the consumer." + ], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.GetArg", + "type": "Interface", + "tags": [], + "label": "GetArg", + "description": [ + "\nGet a file" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.GetArg.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique ID of file metadata" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.GetByIdArgs", + "type": "Interface", + "tags": [], + "label": "GetByIdArgs", + "description": [ + "\nArguments to get a file by ID." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.GetByIdArgs.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nFile ID." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.GetByIdArgs.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nFile kind, must correspond to a registered {@link FileKind}." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.GetUsageMetricsArgs", + "type": "Interface", + "tags": [], + "label": "GetUsageMetricsArgs", + "description": [ + "\nArgs to get usage metrics" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.GetUsageMetricsArgs.ES_FIXED_SIZE_INDEX_BLOB_STORE", + "type": "Object", + "tags": [], + "label": "[ES_FIXED_SIZE_INDEX_BLOB_STORE]", + "description": [ + "\nThe ES backed fixed size storage" + ], + "signature": [ + "{ capacity: number; }" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.ListArg", + "type": "Interface", + "tags": [], + "label": "ListArg", + "description": [], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArg", + "text": "ListArg" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + } + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.ListArg.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nThe file kind to scope this query to" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.ListArgs", + "type": "Interface", + "tags": [], + "label": "ListArgs", + "description": [ + "\nArguments for listing file shares." + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListArgs", + "text": "ListArgs" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + } + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.ListArgs.fileId", + "type": "string", + "tags": [], + "label": "fileId", + "description": [ + "\nThe file ID for scope the list to." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.ListFilesArgs", + "type": "Interface", + "tags": [], + "label": "ListFilesArgs", + "description": [ + "\nArguments list files." + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.ListFilesArgs", + "text": "ListFilesArgs" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.Pagination", + "text": "Pagination" + } + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.ListFilesArgs.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nFile kind, must correspond to a registered {@link FileKind}." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs", + "type": "Interface", + "tags": [], + "label": "UpdateArgs", + "description": [ + "\nUpdate a file args" + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.UpdateArgs", + "text": "UpdateArgs" + }, + "" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nA unique file ID." + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [ + "\nThe file's metadata." + ], + "signature": [ + "{ name?: string | undefined; created?: string | undefined; Status?: \"AWAITING_UPLOAD\" | \"UPLOADING\" | \"READY\" | \"UPLOAD_ERROR\" | \"DELETED\" | undefined; Updated?: string | undefined; mime_type?: string | undefined; size?: number | undefined; hash?: { [hashName: string]: string | undefined; md5?: string | undefined; sha1?: string | undefined; sha256?: string | undefined; sha384?: string | undefined; sha512?: string | undefined; ssdeep?: string | undefined; tlsh?: string | undefined; } | undefined; extension?: string | undefined; Alt?: string | undefined; ChunkSize?: number | undefined; Compression?: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileCompression", + "text": "FileCompression" + }, + " | undefined; FileKind?: string | undefined; Meta?: M | undefined; }" + ], + "path": "x-pack/plugins/files/server/file_client/file_metadata_client/file_metadata_client.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs", + "type": "Interface", + "tags": [], + "label": "UpdateArgs", + "description": [ + "\nUpdate file share arguments." + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nThe file share ID." + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateArgs.attributes", + "type": "Object", + "tags": [], + "label": "attributes", + "description": [ + "\nThe updated attributes to store." + ], + "signature": [ + "{ name?: string | undefined; }" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateFileArgs", + "type": "Interface", + "tags": [], + "label": "UpdateFileArgs", + "description": [ + "\nArguments to update a file" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.UpdateFileArgs.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nFile ID." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateFileArgs.fileKind", + "type": "string", + "tags": [], + "label": "fileKind", + "description": [ + "\nFile kind, must correspond to a registered {@link FileKind}." + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-server.UpdateFileArgs.attributes", + "type": "Object", + "tags": [], + "label": "attributes", + "description": [ + "\nAttributes to update." + ], + "signature": [ + "{ name: string; meta: unknown; alt: string | undefined; }" + ], + "path": "x-pack/plugins/files/server/file_service/file_action_types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "files", + "id": "def-server.DeleteArgs", + "type": "Type", + "tags": [], + "label": "DeleteArgs", + "description": [ + "\nDelete file share arguments." + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-server.GetArgs", + "type": "Type", + "tags": [], + "label": "GetArgs", + "description": [ + "\nGet file share arguments." + ], + "signature": [ + "IdArg" + ], + "path": "x-pack/plugins/files/server/file_share_service/internal_file_share_service.ts", + "deprecated": false, + "initialIsOpen": false + } + ], + "objects": [], + "setup": { + "parentPluginId": "files", + "id": "def-server.FilesSetup", + "type": "Interface", + "tags": [], + "label": "FilesSetup", + "description": [ + "\nFiles plugin setup contract" + ], + "path": "x-pack/plugins/files/server/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FilesSetup.registerFileKind", + "type": "Function", + "tags": [], + "label": "registerFileKind", + "description": [ + "\nRegister a {@link FileKind} which allows for specifying details about the files\nthat will be uploaded.\n" + ], + "signature": [ + "(fileKind: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileKind", + "text": "FileKind" + }, + ") => void" + ], + "path": "x-pack/plugins/files/server/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FilesSetup.registerFileKind.$1", + "type": "Object", + "tags": [], + "label": "fileKind", + "description": [ + "- the file kind to register" + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileKind", + "text": "FileKind" + } + ], + "path": "x-pack/plugins/files/server/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "files", + "id": "def-server.FilesStart", + "type": "Interface", + "tags": [], + "label": "FilesStart", + "description": [ + "\nFiles plugin start contract" + ], + "path": "x-pack/plugins/files/server/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-server.FilesStart.fileServiceFactory", + "type": "Object", + "tags": [], + "label": "fileServiceFactory", + "description": [ + "\nCreate an instance of {@link FileServiceStart}." + ], + "signature": [ + { + "pluginId": "files", + "scope": "server", + "docId": "kibFilesPluginApi", + "section": "def-server.FileServiceFactory", + "text": "FileServiceFactory" + } + ], + "path": "x-pack/plugins/files/server/types.ts", + "deprecated": false + } + ], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "files", + "id": "def-common.BlobStorageSettings", + "type": "Interface", + "tags": [], + "label": "BlobStorageSettings", + "description": [ + "\nDefines all the settings for supported blob stores.\n\nKey names map to unique blob store implementations and so must not be changed\nwithout a migration" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.BlobStorageSettings.ES_FIXED_SIZE_INDEX_BLOB_STORE", + "type": "Object", + "tags": [], + "label": "[ES_FIXED_SIZE_INDEX_BLOB_STORE]", + "description": [ + "\nSingle index that supports up to 50GB of blobs" + ], + "signature": [ + "{ index: string; } | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.File", + "type": "Interface", + "tags": [], + "label": "File", + "description": [ + "\nA class with set of properties and behaviors of the \"smart\" file object and adds\nbehaviours for interacting with files on top of the pure data." + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + " extends ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.File.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [ + "\nUpdate a file object's metadatathat can be updated.\n" + ], + "signature": [ + "(attr: Partial<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.UpdatableFileMetadata", + "text": "UpdatableFileMetadata" + }, + ">) => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.File", + "text": "File" + }, + ">" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.File.update.$1", + "type": "Object", + "tags": [], + "label": "attr", + "description": [ + "- The of attributes to update." + ], + "signature": [ + "Partial<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.UpdatableFileMetadata", + "text": "UpdatableFileMetadata" + }, + ">" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.uploadContent", + "type": "Function", + "tags": [], + "label": "uploadContent", + "description": [ + "\nStream file content to storage.\n" + ], + "signature": [ + "(content: ", + "Readable", + ") => Promise" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.File.uploadContent.$1", + "type": "Object", + "tags": [], + "label": "content", + "description": [ + "- The content to stream to storage." + ], + "signature": [ + "Readable" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.downloadContent", + "type": "Function", + "tags": [], + "label": "downloadContent", + "description": [ + "\nStream file content from storage." + ], + "signature": [ + "() => Promise<", + "Readable", + ">" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.delete", + "type": "Function", + "tags": [ + "note" + ], + "label": "delete", + "description": [ + "\nDelete a file.\n" + ], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.share", + "type": "Function", + "tags": [ + "note" + ], + "label": "share", + "description": [ + "\nGenerate a secure token that can be used to access a file's content.\n" + ], + "signature": [ + "(opts?: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareOptions", + "text": "FileShareOptions" + }, + " | undefined) => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSONWithToken", + "text": "FileShareJSONWithToken" + }, + ">" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.File.share.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "- Share file options." + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareOptions", + "text": "FileShareOptions" + }, + " | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.listShares", + "type": "Function", + "tags": [], + "label": "listShares", + "description": [ + "\nList all current {@link FileShareJSON} objects that have been created for\na file." + ], + "signature": [ + "() => Promise<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + "[]>" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.unshare", + "type": "Function", + "tags": [], + "label": "unshare", + "description": [ + "\nRemove a {@link FileShareJSON} object therefore ceasing to share a file's\ncontent.\n" + ], + "signature": [ + "(opts: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileUnshareOptions", + "text": "FileUnshareOptions" + }, + ") => Promise" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.File.unshare.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [ + "- Unshare file options" + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileUnshareOptions", + "text": "FileUnshareOptions" + } + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "files", + "id": "def-common.File.toJSON", + "type": "Function", + "tags": [], + "label": "toJSON", + "description": [ + "\nGet a JSON representation of the file. Convenient for serialisation." + ], + "signature": [ + "() => ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON", + "type": "Interface", + "tags": [], + "label": "FileJSON", + "description": [ + "\nAttributes of a file that represent a serialised version of the file." + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileJSON", + "text": "FileJSON" + }, + "" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FileJSON.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique file ID." + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.created", + "type": "string", + "tags": [], + "label": "created", + "description": [ + "\nISO string of when this file was created" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.updated", + "type": "string", + "tags": [], + "label": "updated", + "description": [ + "\nISO string of when the file was updated" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.name", + "type": "string", + "tags": [ + "note" + ], + "label": "name", + "description": [ + "\nFile name.\n" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.mimeType", + "type": "string", + "tags": [], + "label": "mimeType", + "description": [ + "\nMIME type of the file's contents." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.size", + "type": "number", + "tags": [], + "label": "size", + "description": [ + "\nThe size, in bytes, of the file content." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.extension", + "type": "string", + "tags": [ + "note" + ], + "label": "extension", + "description": [ + "\nThe file extension (dot suffix).\n" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.meta", + "type": "Uncategorized", + "tags": [], + "label": "meta", + "description": [ + "\nA consumer defined set of attributes.\n\nConsumers of the file service can add their own tags and identifiers to\na file using the \"meta\" object." + ], + "signature": [ + "Meta | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.alt", + "type": "string", + "tags": [], + "label": "alt", + "description": [ + "\nUse this text to describe the file contents for display and accessibility." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.fileKind", + "type": "string", + "tags": [ + "note" + ], + "label": "fileKind", + "description": [ + "\nA unique kind that governs various aspects of the file. A consumer of the\nfiles service must register a file kind and link their files to a specific\nkind.\n" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileJSON.status", + "type": "CompoundType", + "tags": [], + "label": "status", + "description": [ + "\nThe current status of the file.\n\nSee {@link FileStatus} for more details." + ], + "signature": [ + "\"AWAITING_UPLOAD\" | \"UPLOADING\" | \"READY\" | \"UPLOAD_ERROR\" | \"DELETED\"" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileKind", + "type": "Interface", + "tags": [ + "note" + ], + "label": "FileKind", + "description": [ + "\nA descriptor of meta values associated with a set or \"kind\" of files.\n" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FileKind.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique file kind ID" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileKind.maxSizeBytes", + "type": "number", + "tags": [], + "label": "maxSizeBytes", + "description": [ + "\nMaximum size, in bytes, a file of this kind can be." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileKind.allowedMimeTypes", + "type": "Array", + "tags": [ + "default" + ], + "label": "allowedMimeTypes", + "description": [ + "\nThe MIME type of the file content.\n" + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileKind.blobStoreSettings", + "type": "Object", + "tags": [], + "label": "blobStoreSettings", + "description": [ + "\nBlob store specific settings that enable configuration of storage\ndetails." + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.BlobStorageSettings", + "text": "BlobStorageSettings" + }, + " | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileKind.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [ + "\nOptionally specify which HTTP routes to create for the file kind" + ], + "signature": [ + "{ create?: HttpEndpointDefinition | undefined; update?: HttpEndpointDefinition | undefined; delete?: HttpEndpointDefinition | undefined; getById?: HttpEndpointDefinition | undefined; list?: HttpEndpointDefinition | undefined; download?: HttpEndpointDefinition | undefined; share?: HttpEndpointDefinition | undefined; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON", + "type": "Interface", + "tags": [], + "label": "FileShareJSON", + "description": [ + "\nAttributes of a file that represent a serialised version of the file." + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "\nUnique ID share instance" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON.created", + "type": "string", + "tags": [], + "label": "created", + "description": [ + "\nISO timestamp the share was created" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON.validUntil", + "type": "number", + "tags": [], + "label": "validUntil", + "description": [ + "\nUnix timestamp (in milliseconds) of when this share expires" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nA user-friendly name for the file share" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSON.fileId", + "type": "string", + "tags": [], + "label": "fileId", + "description": [ + "\nThe ID of the file this share is linked to" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareOptions", + "type": "Interface", + "tags": [], + "label": "FileShareOptions", + "description": [ + "\nArguments to pass to share a file" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FileShareOptions.name", + "type": "string", + "tags": [], + "label": "name", + "description": [ + "\nOptional name for the file share, should be human-friendly." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareOptions.validUntil", + "type": "number", + "tags": [ + "note" + ], + "label": "validUntil", + "description": [ + "\nUnix timestamp (in milliseconds) when the file share will expire.\n" + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FilesMetrics", + "type": "Interface", + "tags": [], + "label": "FilesMetrics", + "description": [ + "\nA collection of generally useful metrics about files." + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FilesMetrics.storage", + "type": "Object", + "tags": [], + "label": "storage", + "description": [ + "\nMetrics about all storage media." + ], + "signature": [ + "{ esFixedSizeIndex: { capacity: number; used: number; available: number; }; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FilesMetrics.countByStatus", + "type": "Object", + "tags": [], + "label": "countByStatus", + "description": [ + "\nA count of all files grouped by status" + ], + "signature": [ + "{ AWAITING_UPLOAD: number; UPLOADING: number; READY: number; UPLOAD_ERROR: number; DELETED: number; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.FilesMetrics.countByExtension", + "type": "Object", + "tags": [], + "label": "countByExtension", + "description": [ + "\nA count of all files grouped by extension" + ], + "signature": [ + "{ [x: string]: number; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileUnshareOptions", + "type": "Interface", + "tags": [], + "label": "FileUnshareOptions", + "description": [ + "\nArguments for unsharing a file" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.FileUnshareOptions.shareId", + "type": "string", + "tags": [], + "label": "shareId", + "description": [ + "\nSpecify the share instance to remove" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.Pagination", + "type": "Interface", + "tags": [], + "label": "Pagination", + "description": [ + "\nValues for paginating through results." + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "files", + "id": "def-common.Pagination.page", + "type": "number", + "tags": [], + "label": "page", + "description": [ + "\nPage of results." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + }, + { + "parentPluginId": "files", + "id": "def-common.Pagination.perPage", + "type": "number", + "tags": [], + "label": "perPage", + "description": [ + "\nNumber of results per page." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "files", + "id": "def-common.BaseFileMetadata", + "type": "Type", + "tags": [], + "label": "BaseFileMetadata", + "description": [ + "\nFile metadata fields are defined per the ECS specification:\n\nhttps://www.elastic.co/guide/en/ecs/current/ecs-file.html\n\nCustom fields are named according to the custom field convention: \"CustomFieldName\"." + ], + "signature": [ + "{ name?: string | undefined; mime_type?: string | undefined; created?: string | undefined; size?: number | undefined; hash?: { [hashName: string]: string | undefined; md5?: string | undefined; sha1?: string | undefined; sha256?: string | undefined; sha384?: string | undefined; sha512?: string | undefined; ssdeep?: string | undefined; tlsh?: string | undefined; } | undefined; extension?: string | undefined; Alt?: string | undefined; Updated?: string | undefined; Status?: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileStatus", + "text": "FileStatus" + }, + " | undefined; ChunkSize?: number | undefined; Compression?: ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileCompression", + "text": "FileCompression" + }, + " | undefined; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.ES_FIXED_SIZE_INDEX_BLOB_STORE", + "type": "string", + "tags": [], + "label": "ES_FIXED_SIZE_INDEX_BLOB_STORE", + "description": [ + "\nThe name of the fixed size ES-backed blob store" + ], + "signature": [ + "\"esFixedSizeIndex\"" + ], + "path": "x-pack/plugins/files/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FILE_SO_TYPE", + "type": "string", + "tags": [], + "label": "FILE_SO_TYPE", + "description": [ + "\nUnique type name of the file saved object" + ], + "signature": [ + "\"file\"" + ], + "path": "x-pack/plugins/files/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileCompression", + "type": "Type", + "tags": [], + "label": "FileCompression", + "description": [ + "\nSupported file compression algorithms" + ], + "signature": [ + "\"none\" | \"br\" | \"gzip\" | \"deflate\"" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileMetadata", + "type": "Type", + "tags": [], + "label": "FileMetadata", + "description": [ + "\nExtra metadata on a file object specific to Kibana implementation." + ], + "signature": [ + "Required> & ", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.BaseFileMetadata", + "text": "BaseFileMetadata" + }, + " & { FileKind: string; Meta?: Meta | undefined; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileSavedObject", + "type": "Type", + "tags": [], + "label": "FileSavedObject", + "description": [ + "\nAn {@link SavedObject} containing a file object (i.e., metadata only)." + ], + "signature": [ + "SavedObject", + "<", + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileMetadata", + "text": "FileMetadata" + }, + ">" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShare", + "type": "Type", + "tags": [], + "label": "FileShare", + "description": [ + "\nData stored with a file share object" + ], + "signature": [ + "{ created: string; token: string; name?: string | undefined; valid_until: number; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileShareJSONWithToken", + "type": "Type", + "tags": [ + "note" + ], + "label": "FileShareJSONWithToken", + "description": [ + "\nA version of the file share with a token included.\n" + ], + "signature": [ + { + "pluginId": "files", + "scope": "common", + "docId": "kibFilesPluginApi", + "section": "def-common.FileShareJSON", + "text": "FileShareJSON" + }, + " & { token: string; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.FileStatus", + "type": "Type", + "tags": [], + "label": "FileStatus", + "description": [ + "\nStatus of a file.\n\nAWAITING_UPLOAD - A file object has been created but does not have any contents.\nUPLOADING - File contents are being uploaded.\nREADY - File contents have been uploaded and are ready for to be downloaded.\nUPLOAD_ERROR - An attempt was made to upload file contents but failed.\nDELETED - The file contents have been or are being deleted." + ], + "signature": [ + "\"AWAITING_UPLOAD\" | \"UPLOADING\" | \"READY\" | \"UPLOAD_ERROR\" | \"DELETED\"" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.PLUGIN_ID", + "type": "string", + "tags": [], + "label": "PLUGIN_ID", + "description": [ + "\nThe files plugin ID" + ], + "signature": [ + "\"files\"" + ], + "path": "x-pack/plugins/files/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.PLUGIN_NAME", + "type": "string", + "tags": [], + "label": "PLUGIN_NAME", + "description": [ + "\nThe files plugin name" + ], + "signature": [ + "\"files\"" + ], + "path": "x-pack/plugins/files/common/constants.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.UpdatableFileMetadata", + "type": "Type", + "tags": [], + "label": "UpdatableFileMetadata", + "description": [ + "\nThe set of file metadata that can be updated." + ], + "signature": [ + "{ name: string; meta: Meta | undefined; alt: string | undefined; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "files", + "id": "def-common.UpdatableFileShareMetadata", + "type": "Type", + "tags": [], + "label": "UpdatableFileShareMetadata", + "description": [ + "\nSet of attributes that can be updated in a file share." + ], + "signature": [ + "{ name?: string | undefined; }" + ], + "path": "x-pack/plugins/files/common/types.ts", + "deprecated": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/files.mdx b/api_docs/files.mdx new file mode 100644 index 00000000000000..d6ecff3d673464 --- /dev/null +++ b/api_docs/files.mdx @@ -0,0 +1,55 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibFilesPluginApi +slug: /kibana-dev-docs/api/files +title: "files" +image: https://source.unsplash.com/400x175/?github +description: API docs for the files plugin +date: 2022-08-12 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] +--- +import filesObj from './files.devdocs.json'; + +File upload, download, sharing, and serving over HTTP implementation in Kibana. + +Contact [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/team:AppServicesUx) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 222 | 0 | 3 | 2 | + +## Client + +### Interfaces + + +## Server + +### Setup + + +### Start + + +### Functions + + +### Interfaces + + +### Consts, variables and types + + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 7d050e09570773..31a71fc3ae7537 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -6689,7 +6689,7 @@ "section": "def-common.PackagePolicyPackage", "text": "PackagePolicyPackage" }, - " | undefined; policy_id?: string | undefined; }>) => Promise" + " | undefined; policy_id?: string | undefined; statusCode?: number | undefined; body?: { message: string; } | undefined; }>) => Promise" ], "path": "x-pack/plugins/fleet/server/types/extensions.ts", "deprecated": false, @@ -6712,7 +6712,7 @@ "section": "def-common.PackagePolicyPackage", "text": "PackagePolicyPackage" }, - " | undefined; policy_id?: string | undefined; }>" + " | undefined; policy_id?: string | undefined; statusCode?: number | undefined; body?: { message: string; } | undefined; }>" ], "path": "x-pack/plugins/fleet/server/types/extensions.ts", "deprecated": false @@ -9758,7 +9758,7 @@ "label": "install_source", "description": [], "signature": [ - "\"registry\" | \"upload\" | \"bundled\"" + "\"upload\" | \"registry\" | \"bundled\"" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false @@ -9908,7 +9908,7 @@ "label": "installSource", "description": [], "signature": [ - "\"registry\" | \"upload\" | \"bundled\"" + "\"upload\" | \"registry\" | \"bundled\"" ], "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", "deprecated": false @@ -12835,7 +12835,7 @@ "section": "def-common.PackagePolicyPackage", "text": "PackagePolicyPackage" }, - " | undefined; policy_id?: string | undefined; }[]" + " | undefined; policy_id?: string | undefined; statusCode?: number | undefined; body?: { message: string; } | undefined; }[]" ], "path": "x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 9bb727824c189b..d082db751f29b0 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 33748702b61b8b..909fb6db71fa9f 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index cd3147cc301bd0..374d0324b84688 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index e828742670e19e..2641946dfb5d96 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index c4d0c091519f77..0c21bbf8503831 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 58f393c23bc6f2..b472a8bd4dce55 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 5b5f9f42f9bdcf..a2667f07a82c22 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 76159a88a4046b..bd09dff4d5ad23 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index ad13f5ee9c2d0f..cf1d2b2793f96d 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index d52a5f6b909c30..c9a7c5cba031c4 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 149c07f9a66530..3c7d3231317660 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 4e3fd64430fe4a..c4bed8e82d1f5b 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 441f3eb3db7416..344560be99e683 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index c1f06d561d0447..c857d6f8ed5f2e 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index d9fab71d985946..54d8981baea5c2 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 2201f02c575586..146825795c3662 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 8e48be19e49b8e..9dd3d376afebcd 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 0f8b6675aa3b3c..94ab8f27b94dd5 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 6ee6654bca6279..171ff244c05cb7 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 552bd53fc92307..2714ea6d8577df 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 5511c5405411fa..e19ecb54ee02b2 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bazel_packages.mdx b/api_docs/kbn_bazel_packages.mdx index 3f72ba8df808af..4784ec3ef2e5a3 100644 --- a/api_docs/kbn_bazel_packages.mdx +++ b/api_docs/kbn_bazel_packages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bazel-packages title: "@kbn/bazel-packages" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bazel-packages plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-packages'] --- import kbnBazelPackagesObj from './kbn_bazel_packages.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index e000823006bae0..e266e03093be08 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index b4c7822027657a..6e45b6f0cfba54 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 124fdda39cd951..c1f21a017e60ff 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index a4432f832ef5e2..577de6562d28b5 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index ae5cd47cda8166..47ecc581b2a8a8 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 2d89d9f9d3d278..7c0ed5982c33a1 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index fc93f0c95c25df..5a3045feb68b3a 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 3f692e8c39e74f..7d305e7e63cffe 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index dc25d37e8dcb60..7660bd6e891572 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 6ed61554c64dc3..4b5a256617012c 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 083459d82e7349..0c72e5bcf35a61 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index eabbc9e8244607..b59526abd8cb4b 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index e85565987a37e7..bcb3501bf7c442 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 2e7d30f0d0fbf6..17711b40f7c5b8 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 34de7d4b8e06ac..f5372a8520bddd 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 573b7df56d3c32..01075aec49c4f4 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 18e83415fc77b1..f2ba52135d748c 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 90308821b16024..d4b18bbb33be49 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 5c9813c841e937..6cdb3636db8563 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 2d74140d25d5be..7641ce1a3dc55c 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 5864db03de0713..0ebb4914e568a7 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 980aeb7e5eafd1..41f260c51281fb 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index c7b4f1f1db12ea..14ed25ec89eb2b 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index b51f5542dcac56..4ead28256fa50b 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index ae1d2d010d9ce6..fe5785d68b5685 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index ef822626f6f334..111a9678d7585c 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 5b70ecb0321513..c62b8e8b7d3080 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index c153294c409c34..5eb8ac51030e73 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 5bb7687740ecf0..70df101219287f 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 2cd86fe9ad73bb..36b7875e0984a2 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index ed0b4b1c9bcfdf..9c20a28d6a83b8 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 2bb6fd38a54867..e865a9df76d2aa 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index f5f44e819ce927..8fc8b258ccc5ce 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index fcb6bee1f95ca9..f46c60234b9d79 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 0b469954356942..a4325480547ae9 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index 10f74250c8dd0b..c91ddbd9f11526 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index b84b68e017374d..7513df9ab8dbef 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 1f6edae3523a87..4999951ddfac0a 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 400b5a8cd8d618..38932f55771276 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 5756f10d510006..f82cd891c41a85 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 1775cf95424b56..be92e556cacbdc 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 0fbd1783b6c313..540781b0ba16bd 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index b80f7f7829f3ff..40811c556221fc 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 5894717106f89b..e385eaa2668c3b 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index 788d6e2d1202f6..915a7f8b2ddf2a 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index b21295fde28b6e..e3c7df51fa6b8c 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 4c0375f75ef49d..dbdd6459d2e518 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 741b7b15181ede..44a9a19a8beecd 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 7a748adae2e2bd..4bdf3fef3f58b1 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index c2ced4707e7e2d..7442cdacdf8d81 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index a450f828cc24b8..cd8c00cfa4b9ad 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 660e16aaa23345..45870fcc62353b 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 281c9400435f23..3afe4b00811151 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 6736f3e83167d2..128cba57dd0607 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index c82bdcaec983f3..85fb5e781031a3 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index dc7f6893d73970..c3d1ce1f31f65a 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 29a450346c4469..3a8b16e864fc5f 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 0345e27a252c4c..cf5a297be03c85 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 104d153f003fec..1cf01cba1583b7 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 23d3b5fd4460ea..05d16105fddf3f 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 8f36ee7e2ce4d2..27b9f113012051 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 8569ab0f0bb05a..29f221d8d4b40e 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index ca4ceef547462a..38ced068932805 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index aacfe4c584c299..e5c30d44951cf3 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 39dbbf64c899a6..3100f94c6fbbca 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 1362bd713e36e4..fba8d705f2e7fd 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 71bc6f3a3f04a4..1a41414b030d75 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 041ef87b429526..ac605bea7bf1dd 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index ae16ec053bb116..5406af3d31411c 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index b4a898c163d5a2..2bc582e90b0946 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index ae5b022c353d8f..d28742c30b9888 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser_internal.mdx b/api_docs/kbn_core_mount_utils_browser_internal.mdx index 31eef32ff122da..8f9634237c0113 100644 --- a/api_docs/kbn_core_mount_utils_browser_internal.mdx +++ b/api_docs/kbn_core_mount_utils_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser-internal title: "@kbn/core-mount-utils-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser-internal'] --- import kbnCoreMountUtilsBrowserInternalObj from './kbn_core_mount_utils_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 46bc2f98e711d2..22ee030cf99f27 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 32bdf17e3702da..f8bd621e665aa7 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 1c237f65329ecc..369168adc9872e 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 2f29364b23a433..e01fe56ffc4526 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 7616c2e3e5d19a..d34763678fe9c1 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 0fcdf7624cf5b3..b5347cc28232b2 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 453c38659a5e4d..ab8868a07da0d9 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index a34142a2fae29a..0ec6f64774d2c8 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 37408d1a0c8e00..cd190d6be658fd 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 9a7c7a1edce558..befe7dbc78dde7 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 0afd2e4c96dea5..433c3b74046f95 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index f4c2d6f9ccc42c..8a2b2c86629248 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 8fc0b694aa6c1e..7bc944a1744066 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 24b3e5da37fbbd..f3f64481ab63f6 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 032339de4038f4..54bceb3af713e5 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 038b770a93bac6..174041d53b777f 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 1d5aaa46503482..70beeb5d4b395b 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 52b21777a44360..15e4a4eea98944 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 787255afdcef68..2f50bc329375d6 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 5324e74eaddf4a..df3b944fedd3e7 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 607691e3099a32..802a4ebcf6395a 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index d2d25970198faa..020ea3c7636d9a 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index dd78cb97c9b73c..78bd187f4c3c86 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 319ea1a3816db5..3bf7552d49940d 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index dbf6c57f3a902f..a93c6ef3a61477 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 6cd80192464350..4d8f2dd3e16814 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 23df6c2264954d..0a7c112dd7576b 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 7d308692aa3d3c..c3ebc72eed7804 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 2880bdaed08ba3..188df2f5441ca7 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index b72576e13c035c..6aa997b5c466c5 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index d55689dd7adfaa..cf68438cf4a5e3 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index e2a3d8828c9de0..e63dadd5714b31 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 43f9f57f375482..83dd84b55fdf21 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index e92051ab7b1df1..f465575277f02a 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 278485fada271d..16ef040b2c02a7 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -510,7 +510,7 @@ "label": "securitySolution", "description": [], "signature": [ - "{ readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly threatIntelInt: string; }" + "{ readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly threatIntelInt: string; readonly responseActions: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index c0c47f70125cd5..6a90a111b88b95 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 7d67005ca5e99c..b16bb3e14ec18e 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index baed6476694f03..68cae1c2597827 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index fb0b15352818bd..6cf9fcc6c1388a 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 3484f1a6ada512..bdc74d77ea7276 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index eade19c03aa863..7732edadb6e8a6 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 9a7b139bc2a523..957e805ebb4a96 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index e31c681e7ba4d7..95a7ff3522eac3 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 188031bf41fcc6..e186d4e9d11281 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index a77e974d22f041..5874545b2c8bf6 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index 8e464bd8f0012b..4d215ddc233be4 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 72a4fe984177fb..6450376350f488 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 2c309c2f64a286..76b9ff7e00417b 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 889d0c17237d9b..7e3e84e109a60e 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 956443176eec36..56453c2aa1305d 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 3b55fb665b7731..cfce1312687404 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 18cedf5f5e4f89..0dd41730c796f4 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 09163c26a680d8..c6ded2784dc93f 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index bb1c0bedada868..387c7b42158c47 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 20a4d28a0221ef..77ec8bfb2e9496 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_parser.mdx b/api_docs/kbn_kibana_manifest_parser.mdx index 8d12a00d7354ae..121c3aded4ff04 100644 --- a/api_docs/kbn_kibana_manifest_parser.mdx +++ b/api_docs/kbn_kibana_manifest_parser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-parser title: "@kbn/kibana-manifest-parser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-parser plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-parser'] --- import kbnKibanaManifestParserObj from './kbn_kibana_manifest_parser.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 5f16371077c036..29e1975360ac3d 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 48d05d099c986d..2c4aa4bb30ee75 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index f3e37ddd2f7990..b05aee50e3a69e 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index cdcc007bda5475..95dac210ca843c 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 71af48ec9a4dd1..dcbb79753cb64e 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 4f3afabcbdf20f..8355ababc0c25a 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index fd25d71911ac48..d6c77f5d8bc0f5 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 84f80a8557221c..128a8bb64278cc 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 2c037730f69efc..a12486f9af1944 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 99c81b283e5eb7..a51cc04a49d0f1 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 500fd91a654e36..dd12a0d1a69648 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.devdocs.json b/api_docs/kbn_performance_testing_dataset_extractor.devdocs.json index bf86f26e325e73..9b491e72214806 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.devdocs.json +++ b/api_docs/kbn_performance_testing_dataset_extractor.devdocs.json @@ -19,7 +19,9 @@ "label": "extractor", "description": [], "signature": [ - "({ param, client, log }: CLIParams) => Promise" + "({ param, client, log }: ", + "CLIParams", + ") => Promise" ], "path": "packages/kbn-performance-testing-dataset-extractor/src/extractor.ts", "deprecated": false, diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 84fe13cd647f3a..554ca493fd640f 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3 | 0 | 3 | 0 | +| 3 | 0 | 3 | 1 | ## Server diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 7a4b18b12d6f8d..f70ea14f6b9fa1 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 8fef2ea69e8fac..657d1147a2ab40 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index b03dc56faba874..49219e9969bde9 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 55d597dc0f2a91..494cffc27916ee 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 65475404e39084..7eb128aaaaaa65 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 0eb32869202449..c4ea8ef9d504f2 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 3fd73ca86c922a..78406b4a724a61 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 059651e0c5a5a6..20ebf8e5acf0d3 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 7f4324a0e17724..900a580ae5e8be 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 985ca5901286b3..82cbe0a0d4b635 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 4afc55fb373bad..b310d704a3f503 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 5c756ed317cae8..7fe2e2e2fe66ee 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index cfdfd9a6568c6a..13450fbd2b9841 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index f2c6e31617cf89..c19de7f7f9bff1 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index b25c0b1deb60d4..1aef102196d97c 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index fcbcb384848c24..23941613e18873 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 558fcb7778dc36..25ed27060a1e82 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 8d8bebe8fc2001..9ebb3aa9d19ce2 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 98a042e1ed2332..4149ae977d2a9e 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index a1ba58192aaa9a..971ed207005913 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index bce8de0772e484..017190613ce76a 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 602b7900da2ca6..7ddf129b88522a 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 36fa3bff8a0568..691bcdbcdc1d65 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 5900fcefa5a239..09523d1461cbb6 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index f9f761e93c106a..416a994f3e38f6 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 4b4a6a247c8b83..ecb1b66a9a958a 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_components.mdx b/api_docs/kbn_shared_ux_components.mdx index d69138c6435ae4..5014bb65357e62 100644 --- a/api_docs/kbn_shared_ux_components.mdx +++ b/api_docs/kbn_shared_ux_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-components title: "@kbn/shared-ux-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-components plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-components'] --- import kbnSharedUxComponentsObj from './kbn_shared_ux_components.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index a4cc2d4b26bb12..8abe2a7267af4d 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 25689321f7f8cd..78ef2b276011db 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 6fd9be7b546a09..5e52b9f126bd5d 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index 5c4f74b5ad4fa6..718da94d79fc3c 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 70ab9a10e94350..7698b445ba1386 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index bf61fc483d6c50..9fc8a820509f93 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 8a24fe051e71a7..4e914ac9b7a2e3 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index bb254d68a98c3e..74cc77659dbe4c 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_services.mdx b/api_docs/kbn_shared_ux_services.mdx index bd1958f97749e6..20d75b5d8c032c 100644 --- a/api_docs/kbn_shared_ux_services.mdx +++ b/api_docs/kbn_shared_ux_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-services title: "@kbn/shared-ux-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-services plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-services'] --- import kbnSharedUxServicesObj from './kbn_shared_ux_services.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook.mdx b/api_docs/kbn_shared_ux_storybook.mdx index a13e4cceb4d0c4..01d0a6d33a75a8 100644 --- a/api_docs/kbn_shared_ux_storybook.mdx +++ b/api_docs/kbn_shared_ux_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook title: "@kbn/shared-ux-storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook'] --- import kbnSharedUxStorybookObj from './kbn_shared_ux_storybook.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 49725a3f13e479..e4db811ed9d6cf 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 364e61e82fd8a0..45fa004c5aa241 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 7f40f129763d06..7ccece8477122f 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index 825cbae993202e..fd65b4e75c83a7 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 6bbc561c4830f1..fd67cdb263ff7e 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 1f6b56839503a1..5b1dd4e5f00ac5 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index d5c5ecd9710615..209986ce59906b 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index eb842010913da7..1fa6095718a774 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 81468659ef8d1c..dba34e047a46bd 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 218032a0205ceb..171a31237bc64b 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index e04ac886039e93..ccb27f11676252 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index b93458fcfd6f3c..79232699be356f 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index 09973a0355c1a7..fec9e40968fa37 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index fc803c91fe2278..2f1320b32455ae 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 0b8adb42b2510c..713fbbe27dbff2 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 49b6b5b49565de..a3e43cbf7b71a8 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 53d0fa73d9ee07..abe416c7fd7340 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index bdecfc73f4ebc1..ee4f48ade54ea6 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index b546f76fbb408e..6a605cc60dc48b 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 7b193b75ddcbc9..43319d66aca984 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 9b707bb0c7dcf3..a5fd18ea95d0bb 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 8c7f62aba14141..1374241f425e64 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index e56406b94b4c5e..648bc4c96a52c7 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 48713acc4b59ae..1ff9601f153f6a 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index ec3a260fc858ec..cd8119c9647089 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -967,6 +967,19 @@ ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisExtentConfig.enforce", + "type": "CompoundType", + "tags": [], + "label": "enforce", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false } ], "initialIsOpen": false @@ -1294,6 +1307,26 @@ ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.curveType", + "type": "CompoundType", + "tags": [], + "label": "curveType", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XYCurveType", + "text": "XYCurveType" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false } ], "initialIsOpen": false @@ -5819,26 +5852,6 @@ "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false }, - { - "parentPluginId": "lens", - "id": "def-public.XYArgs.curveType", - "type": "CompoundType", - "tags": [], - "label": "curveType", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XYCurveType", - "text": "XYCurveType" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false - }, { "parentPluginId": "lens", "id": "def-public.XYArgs.fillOpacity", @@ -7200,7 +7213,7 @@ "label": "FittingFunction", "description": [], "signature": [ - "\"None\" | \"Zero\" | \"Linear\" | \"Carry\" | \"Lookahead\"" + "\"None\" | \"Zero\" | \"Nearest\" | \"Linear\" | \"Carry\" | \"Lookahead\" | \"Average\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, @@ -7384,7 +7397,7 @@ "label": "LineStyle", "description": [], "signature": [ - "\"solid\" | \"dashed\" | \"dotted\"" + "\"solid\" | \"dashed\" | \"dotted\" | \"dot-dashed\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, @@ -7813,7 +7826,7 @@ "label": "XYCurveType", "description": [], "signature": [ - "\"LINEAR\" | \"CURVE_MONOTONE_X\"" + "\"LINEAR\" | \"CURVE_MONOTONE_X\" | \"CURVE_STEP_AFTER\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 79cab2a0c391be..b1fbb0812947d8 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 613 | 0 | 529 | 40 | +| 614 | 0 | 530 | 40 | ## Client diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index aba6b167cae5a2..d86e6d93dc2e79 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 812fddd90eaa46..f025f193268bf2 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 5e24095c695cfb..af6fa07cf102a7 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 650ae2c4029524..e7ec756816f96e 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index bd6c4e20be181f..870169134ea41a 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 3b773461df2443..78af7289e0a8da 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 70e163489b0a0d..a507abfe84b765 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 8e72f2881a7b40..c6d1ae2c099f9c 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 35d5950e9aa09a..bfa578825b82eb 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 99444b3ab8c4f3..1eaddff352fb27 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 3e6e703b2627f5..b7940e1561d3fd 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 4c27826c7d70d1..d0c712b3a5c19f 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index beb1f8ed4ce00b..0c7da0b68db006 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 932943299b4d5c..91713117812736 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 5edc8ff33896b9..7cb90bf7813614 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
    public API | Number of teams | |--------------|----------|------------------------| -| 401 | 335 | 36 | +| 402 | 336 | 37 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 28894 | 175 | 19605 | 911 | +| 29119 | 175 | 19610 | 912 | ## Plugin Directory @@ -74,11 +74,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'revealImage' function and renderer to expressions | 14 | 0 | 14 | 3 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 148 | 0 | 146 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 7 | 0 | 7 | 0 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 150 | 0 | 140 | 14 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 151 | 0 | 141 | 12 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds expression runtime to Kibana | 2183 | 17 | 1729 | 5 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 222 | 0 | 95 | 2 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 288 | 5 | 249 | 3 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 62 | 0 | 62 | 2 | +| | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/team:AppServicesUx) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 222 | 0 | 3 | 2 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 955 | 3 | 860 | 9 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | @@ -98,7 +99,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | kibanaUsageCollection | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 0 | 0 | 0 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 615 | 3 | 420 | 9 | | | [Security Team](https://github.com/orgs/elastic/teams/security-team) | - | 3 | 0 | 3 | 1 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 613 | 0 | 529 | 40 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 614 | 0 | 530 | 40 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 8 | 0 | 8 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 3 | 0 | 3 | 0 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 10 | @@ -128,7 +129,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 32 | 0 | 13 | 0 | | | [Kibana Reporting Services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 4 | | searchprofiler | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 239 | 0 | 90 | 0 | +| | [Platform Security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 240 | 0 | 90 | 0 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 54 | 0 | 53 | 22 | | | [Security Team](https://github.com/orgs/elastic/teams/security-team) | - | 3 | 0 | 3 | 1 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 114 | 0 | 55 | 10 | @@ -328,7 +329,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 55 | 0 | 55 | 2 | | | [Owner missing] | - | 47 | 0 | 46 | 10 | | | [Owner missing] | - | 51 | 5 | 34 | 0 | -| | [Owner missing] | A library to convert APM traces into JSON format for performance testing. | 3 | 0 | 3 | 0 | +| | [Owner missing] | A library to convert APM traces into JSON format for performance testing. | 3 | 0 | 3 | 1 | | | [Owner missing] | - | 1 | 0 | 1 | 0 | | | [Owner missing] | Just some helpers for kibana plugin devs. | 1 | 0 | 1 | 0 | | | [Owner missing] | - | 21 | 0 | 10 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 4941daae32dd95..51bdd4793fdaee 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 8d4396be9bf197..5bf09d2ec27a9c 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 6aee86e0fdf60d..7ef85b3c53a3e9 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 023133740bb35f..1008b5353d44ba 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 932775d59d1f86..ff839a65ff9e85 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index c8f4bbb7cfd547..e129f3cfe9dfb4 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 2a45acec975d7e..fdf50f535fddba 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 5aedc341f2015e..8f4e7c8fad70bd 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index fcdc28e1902916..fa32f2b5b42730 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index b20c324fc17527..2ff96f48f3ada0 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 33de999c004878..041c2a214304be 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 8d5a646481901d..fafd168432042e 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index 11dfcb65020ff4..a4c9ed1ec2847d 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -3800,6 +3800,18 @@ "path": "x-pack/plugins/security/common/model/user_profile.ts", "deprecated": false }, + { + "parentPluginId": "security", + "id": "def-common.UserProfile.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nIndicates whether user profile is enabled or not." + ], + "path": "x-pack/plugins/security/common/model/user_profile.ts", + "deprecated": false + }, { "parentPluginId": "security", "id": "def-common.UserProfile.user", diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 706e8aac915466..db3af1b6bc0ea2 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-securit | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 239 | 0 | 90 | 0 | +| 240 | 0 | 90 | 0 | ## Client diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 21c98900020f08..b7bf5a62060d90 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 68180e90389959..7510601cb981e5 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index b573d28030c720..d3460b3178fd12 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/shared_u_x.mdx b/api_docs/shared_u_x.mdx index d6cfa154851886..6946ac8a13c298 100644 --- a/api_docs/shared_u_x.mdx +++ b/api_docs/shared_u_x.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sharedUX title: "sharedUX" image: https://source.unsplash.com/400x175/?github description: API docs for the sharedUX plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sharedUX'] --- import sharedUXObj from './shared_u_x.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index d3d5e104f45260..5aaebe166792e5 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 9038d2eacc9088..d5a515c054aa1d 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index dcdba1552f10a7..ea0197adce4cf6 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index ce359ca4fd7b99..4c9e66efc7a206 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 89a01c83122b2d..3f721b651916e1 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 865e7be0c9551a..af338d1a5f1518 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index b4fa569dbc78be..a2659f9aac83d3 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 486de1a4c8432a..b155bb72164bc1 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index f147d268825a28..7f7e4cb60e46fd 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index b955620c88ff3d..68d1680a514113 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 5f6c713dc50d3f..2ba105a1d8caea 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index d55719923df333..c7306a813fa24d 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 375718734c27e7..5517db4c113177 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index e651863ed5962b..5f9d6869cc2af7 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index a5328347a36256..6f898fb655c8f5 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index d6b1410085d75d..8d75e03ec62053 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index f1422e2da619e1..1764b302a88bf4 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 8c0738785659ab..d6d1c57004a806 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 7b4f36876f174c..9e3acfd826500e 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index d1ca9c17993492..146e6b26048c0b 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 28f78831cc229b..5784ff85ddabcf 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 50e7e19e267365..0dac848a1597ed 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index dc67a737d1e99e..c3b85dc579c749 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index f5d1e470e712b7..cecaf6a753d504 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 078ba6536f657f..1067198b0bc5dc 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 9d18d6a2cb1290..9ee838711df564 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 3b572d668e70ea..3728409426a6b3 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index f7cd6b727ef718..3fe4f1617e384e 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 45160066493f50..dcb5d68ae29c73 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 77bc2d77102e13..0f61bee0777613 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2022-08-11 +date: 2022-08-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From ea7bc3619dddf4c4a4a2b8a71cbd3d9f29eac4b4 Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Fri, 12 Aug 2022 09:42:41 +0200 Subject: [PATCH 37/59] [Enterprise Search] Correctly handle non-alphanumeric index names (#138602) --- .../common/utils/to_alphanumeric.test.ts | 26 +++++++ .../common/utils/to_alphanumeric.ts | 13 ++++ .../search_documents_api_logic.test.ts | 74 +++++++++++++++++++ ...logic.ts => search_documents_api_logic.ts} | 11 ++- .../connector/api_key_configuration.tsx | 1 + .../connector/connector_overview_panels.tsx | 6 +- .../connector/connector_scheduling.tsx | 5 +- .../search_index/documents_logic.test.ts | 2 +- .../search_index/documents_logic.ts | 2 +- .../components/search_index/index_nav.tsx | 23 ++++-- .../search_index/search_index_router.tsx | 2 +- .../search_indices/indices_table.tsx | 9 +-- .../server/lib/indices/create_api_key.ts | 5 +- .../lib/indices/generate_api_key.test.ts | 6 +- .../server/lib/indices/generate_api_key.ts | 3 +- .../routes/enterprise_search/connectors.ts | 39 ++-------- .../enterprise_search/create_api_key.ts | 2 +- .../routes/enterprise_search/indices.ts | 6 +- .../server/routes/enterprise_search/search.ts | 7 +- 19 files changed, 171 insertions(+), 71 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.test.ts create mode 100644 x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.test.ts rename x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/{search_documents_logic.ts => search_documents_api_logic.ts} (78%) diff --git a/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.test.ts b/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.test.ts new file mode 100644 index 00000000000000..97d76e31043f6b --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.test.ts @@ -0,0 +1,26 @@ +/* + * 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 { toAlphanumeric } from './to_alphanumeric'; + +describe('toAlphanumeric', () => { + it('replaces non-alphanumeric characters with dashes', () => { + expect(toAlphanumeric('f1 &&o$ 1 2 *&%da')).toEqual('f1-o-1-2-da'); + }); + + it('strips leading and trailing non-alphanumeric characters', () => { + expect(toAlphanumeric('$$hello world**')).toEqual('hello-world'); + }); + + it('strips leading and trailing whitespace', () => { + expect(toAlphanumeric(' test ')).toEqual('test'); + }); + + it('lowercases text', () => { + expect(toAlphanumeric('SomeName')).toEqual('somename'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.ts b/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.ts new file mode 100644 index 00000000000000..7bb513cfe8b3c5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/utils/to_alphanumeric.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const toAlphanumeric = (input: string) => + input + .trim() + .replace(/[^a-zA-Z0-9]+/g, '-') // Replace all special/non-alphanumerical characters with dashes + .replace(/^[-]+|[-]+$/g, '') // Strip all leading and trailing dashes + .toLowerCase(); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.test.ts new file mode 100644 index 00000000000000..fb0162c8aec15e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.test.ts @@ -0,0 +1,74 @@ +/* + * 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 { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { searchDocuments } from './search_documents_api_logic'; + +describe('SearchDocumentsApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('searchDocuments', () => { + it('calls correct api', async () => { + const promise = Promise.resolve('result'); + http.get.mockReturnValue(promise); + const result = searchDocuments({ + indexName: 'indexName', + pagination: { + pageIndex: 0, + pageSize: 10, + }, + }); + await nextTick(); + expect(http.get).toHaveBeenCalledWith( + '/internal/enterprise_search/indices/indexName/search', + { query: { page: 0, size: 10 } } + ); + await expect(result).resolves.toEqual('result'); + }); + it('calls correct api with query set', async () => { + const promise = Promise.resolve('result'); + http.get.mockReturnValue(promise); + const result = searchDocuments({ + indexName: 'düsseldorf', + pagination: { + pageIndex: 0, + pageSize: 10, + }, + query: 'abcd', + }); + await nextTick(); + expect(http.get).toHaveBeenCalledWith( + '/internal/enterprise_search/indices/d%C3%BCsseldorf/search/abcd', + { query: { page: 0, size: 10 } } + ); + await expect(result).resolves.toEqual('result'); + }); + it('calls with correct pageSize with docsPerPage set', async () => { + const promise = Promise.resolve('result'); + http.get.mockReturnValue(promise); + const result = searchDocuments({ + docsPerPage: 25, + indexName: 'indexName', + pagination: { + pageIndex: 0, + pageSize: 10, + }, + }); + await nextTick(); + expect(http.get).toHaveBeenCalledWith( + '/internal/enterprise_search/indices/indexName/search', + { query: { page: 0, size: 25 } } + ); + await expect(result).resolves.toEqual('result'); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.ts similarity index 78% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_logic.ts rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.ts index b423b00c97ed10..e446522579d070 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/search_documents/search_documents_api_logic.ts @@ -16,14 +16,17 @@ export const searchDocuments = async ({ docsPerPage, indexName, pagination, - query: q, + query: searchQuery, }: { docsPerPage?: number; indexName: string; - pagination: { pageIndex: number; pageSize: number; totalItemCount: number }; - query: string; + pagination: { pageIndex: number; pageSize: number }; + query?: string; }) => { - const route = `/internal/enterprise_search/indices/${indexName}/search/${q}`; + const newIndexName = encodeURIComponent(indexName); + const route = `/internal/enterprise_search/indices/${newIndexName}/search${ + searchQuery ? `/${searchQuery}` : '' + }`; const query = { page: pagination.pageIndex, size: docsPerPage || pagination.pageSize, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/api_key_configuration.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/api_key_configuration.tsx index 19974d4b281b36..14a83cbab01db7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/api_key_configuration.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/api_key_configuration.tsx @@ -17,6 +17,7 @@ import { EuiSpacer, EuiConfirmModal, } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import { Status } from '../../../../../../common/types/api'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_overview_panels.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_overview_panels.tsx index b1fa1aaa378afb..ee56437a7aead7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_overview_panels.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_overview_panels.tsx @@ -7,14 +7,14 @@ import React from 'react'; -import { generatePath } from 'react-router-dom'; - import { useValues } from 'kea'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiStat } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { generateEncodedPath } from '../../../../shared/encode_path_params'; + import { EuiLinkTo } from '../../../../shared/react_router_helpers'; import { SEARCH_INDEX_TAB_PATH } from '../../../routes'; @@ -78,7 +78,7 @@ export const ConnectorOverviewPanels: React.FC = () => { {ingestionStatus === IngestionStatus.INCOMPLETE ? ( { { const navItems: Array> = [ { + 'data-test-subj': 'IndexLabel', id: 'indexName', name: indexName, renderItem: () => ( @@ -35,40 +37,45 @@ export const useSearchIndicesNav = () => {
    {indexName.toUpperCase()}
    ), - 'data-test-subj': 'IndexLabel', }, { + 'data-test-subj': 'IndexOverviewLink', id: SearchIndexTabId.OVERVIEW, name: i18n.translate('xpack.enterpriseSearch.content.searchIndex.nav.overviewTitle', { defaultMessage: 'Overview', }), ...generateNavLink({ - to: generatePath(SEARCH_INDEX_TAB_PATH, { indexName, tabId: SearchIndexTabId.OVERVIEW }), + to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { + indexName, + tabId: SearchIndexTabId.OVERVIEW, + }), }), - 'data-test-subj': 'IndexOverviewLink', }, { + 'data-test-subj': 'IndexDocumentsLink', id: SearchIndexTabId.DOCUMENTS, name: i18n.translate('xpack.enterpriseSearch.content.searchIndex.nav.documentsTitle', { defaultMessage: 'Documents', }), ...generateNavLink({ - to: generatePath(SEARCH_INDEX_TAB_PATH, { indexName, tabId: SearchIndexTabId.DOCUMENTS }), + to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { + indexName, + tabId: SearchIndexTabId.DOCUMENTS, + }), }), - 'data-test-subj': 'IndexDocumentsLink', }, { + 'data-test-subj': 'IndexIndexMappingsLink', id: SearchIndexTabId.INDEX_MAPPINGS, name: i18n.translate('xpack.enterpriseSearch.content.searchIndex.nav.indexMappingsTitle', { defaultMessage: 'Index Mappings', }), ...generateNavLink({ - to: generatePath(SEARCH_INDEX_TAB_PATH, { + to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { indexName, tabId: SearchIndexTabId.INDEX_MAPPINGS, }), }), - 'data-test-subj': 'IndexIndexMappingsLink', }, ]; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index_router.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index_router.tsx index 2dc5ff8d059c9e..58a4cd782c5e25 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index_router.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index_router.tsx @@ -23,7 +23,7 @@ import { IndexViewLogic } from './index_view_logic'; import { SearchIndex } from './search_index'; export const SearchIndexRouter: React.FC = () => { - const { indexName } = useParams<{ indexName: string }>(); + const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName); const indexNameLogic = IndexNameLogic({ indexName }); const { setIndexName } = useActions(indexNameLogic); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx index 572f2b9dae616b..d68ce14b1b1838 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx @@ -7,8 +7,6 @@ import React from 'react'; -import { generatePath } from 'react-router-dom'; - import { CriteriaWithPagination, EuiBasicTable, @@ -19,6 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { Meta } from '../../../../../common/types'; +import { generateEncodedPath } from '../../../shared/encode_path_params'; import { EuiLinkTo, EuiButtonIconTo } from '../../../shared/react_router_helpers'; import { EuiBadgeTo } from '../../../shared/react_router_helpers/eui_components'; import { convertMetaToPagination } from '../../../shared/table_pagination'; @@ -47,7 +46,7 @@ const columns: Array> = [ render: (name: string) => ( {name} @@ -102,7 +101,7 @@ const columns: Array> = [ } ), render: (index: ElasticsearchViewIndex) => { - const overviewPath = generatePath(SEARCH_INDEX_PATH, { indexName: index.name }); + const overviewPath = generateEncodedPath(SEARCH_INDEX_PATH, { indexName: index.name }); if (isCrawlerIndex(index)) { const label = crawlerStatusToText(index.crawler?.most_recent_crawl_request_status); @@ -135,7 +134,7 @@ const columns: Array> = [ aria-label={name} iconType="eye" data-test-subj="view-search-index-button" - to={generatePath(SEARCH_INDEX_PATH, { + to={generateEncodedPath(SEARCH_INDEX_PATH, { indexName: name, })} /> diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/create_api_key.ts b/x-pack/plugins/enterprise_search/server/lib/indices/create_api_key.ts index f59ce222c7d28e..0c1a62c4d30db0 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/create_api_key.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/create_api_key.ts @@ -6,8 +6,11 @@ */ import { KibanaRequest } from '@kbn/core/server'; + import { SecurityPluginStart } from '@kbn/security-plugin/server'; +import { toAlphanumeric } from '../../../common/utils/to_alphanumeric'; + export const createApiKey = async ( request: KibanaRequest, security: SecurityPluginStart, @@ -17,7 +20,7 @@ export const createApiKey = async ( return await security.authc.apiKeys.create(request, { name: keyName, role_descriptors: { - [`${indexName}-key-role`]: { + [`${toAlphanumeric(indexName)}-key-role`]: { cluster: [], index: [ { diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts index e240f4c5278742..0ff9800716cfe3 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.test.ts @@ -55,7 +55,7 @@ describe('generateApiKey lib function', () => { expect(mockClient.asCurrentUser.security.createApiKey).toHaveBeenCalledWith({ name: 'index_name-connector', role_descriptors: { - ['index_name-connector-role']: { + ['index-name-connector-role']: { cluster: [], index: [ { @@ -90,7 +90,7 @@ describe('generateApiKey lib function', () => { expect(mockClient.asCurrentUser.security.createApiKey).toHaveBeenCalledWith({ name: 'index_name-connector', role_descriptors: { - ['index_name-connector-role']: { + ['index-name-connector-role']: { cluster: [], index: [ { @@ -137,7 +137,7 @@ describe('generateApiKey lib function', () => { expect(mockClient.asCurrentUser.security.createApiKey).toHaveBeenCalledWith({ name: 'index_name-connector', role_descriptors: { - ['index_name-connector-role']: { + ['index-name-connector-role']: { cluster: [], index: [ { diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts index 9947ad56319a50..a6d3455f918974 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/generate_api_key.ts @@ -9,12 +9,13 @@ import { IScopedClusterClient } from '@kbn/core/server'; import { CONNECTORS_INDEX } from '../..'; import { ConnectorDocument } from '../../../common/types/connectors'; +import { toAlphanumeric } from '../../../common/utils/to_alphanumeric'; export const generateApiKey = async (client: IScopedClusterClient, indexName: string) => { const apiKeyResult = await client.asCurrentUser.security.createApiKey({ name: `${indexName}-connector`, role_descriptors: { - [`${indexName}-connector-role`]: { + [`${toAlphanumeric(indexName)}-connector-role`]: { cluster: [], index: [ { diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts index 015567712d6484..b54ab3bb0e8484 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts @@ -73,17 +73,8 @@ export function registerConnectorRoutes({ router, log }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - try { - await updateConnectorConfiguration(client, request.params.connectorId, request.body); - return response.ok(); - } catch (error) { - return response.customError({ - body: i18n.translate('xpack.enterpriseSearch.server.routes.updateConnector.error', { - defaultMessage: 'Error fetching data from Enterprise Search', - }), - statusCode: 502, - }); - } + await updateConnectorConfiguration(client, request.params.connectorId, request.body); + return response.ok(); }) ); @@ -99,17 +90,8 @@ export function registerConnectorRoutes({ router, log }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - try { - await updateConnectorScheduling(client, request.params.connectorId, request.body); - return response.ok(); - } catch (error) { - return response.customError({ - body: i18n.translate('xpack.enterpriseSearch.server.routes.updateConnector.error', { - defaultMessage: 'Error fetching data from Enterprise Search', - }), - statusCode: 502, - }); - } + await updateConnectorScheduling(client, request.params.connectorId, request.body); + return response.ok(); }) ); @@ -124,17 +106,8 @@ export function registerConnectorRoutes({ router, log }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - try { - await startConnectorSync(client, request.params.connectorId); - return response.ok(); - } catch (error) { - return response.customError({ - body: i18n.translate('xpack.enterpriseSearch.server.routes.updateConnector.error', { - defaultMessage: 'Error fetching data from Enterprise Search', - }), - statusCode: 502, - }); - } + await startConnectorSync(client, request.params.connectorId); + return response.ok(); }) ); } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/create_api_key.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/create_api_key.ts index da3b8c736146ea..d2287831dc6eb1 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/create_api_key.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/create_api_key.ts @@ -30,7 +30,7 @@ export function registerCreateAPIKeyRoute( }, }, elasticsearchErrorHandler(log, async (context, request, response) => { - const { indexName } = request.params; + const indexName = decodeURIComponent(request.params.indexName); const { keyName } = request.body; const createResponse = await createApiKey(request, security, indexName, keyName); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index bf44bab16fc2a9..25ecd295ceb359 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -100,7 +100,7 @@ export function registerIndexRoutes({ router, log }: RouteDependencies) { }, }, elasticsearchErrorHandler(log, async (context, request, response) => { - const { indexName } = request.params; + const indexName = decodeURIComponent(request.params.indexName); const { client } = (await context.core).elasticsearch; try { @@ -134,7 +134,7 @@ export function registerIndexRoutes({ router, log }: RouteDependencies) { }, }, elasticsearchErrorHandler(log, async (context, request, response) => { - const { indexName } = request.params; + const indexName = decodeURIComponent(request.params.indexName); const { client } = (await context.core).elasticsearch; let indexExists: boolean; @@ -172,7 +172,7 @@ export function registerIndexRoutes({ router, log }: RouteDependencies) { }, }, elasticsearchErrorHandler(log, async (context, request, response) => { - const { indexName } = request.params; + const indexName = decodeURIComponent(request.params.indexName); const { client } = (await context.core).elasticsearch; const apiKey = await generateApiKey(client, indexName); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/search.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/search.ts index ee57f4a59c5684..7e51d00aa25370 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/search.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/search.ts @@ -54,13 +54,13 @@ export function registerSearchRoute({ router, log }: RouteDependencies) { }, }, elasticsearchErrorHandler(log, async (context, request, response) => { + const indexName = decodeURIComponent(request.params.index_name); const { client } = (await context.core).elasticsearch; const { page = 0, size = ENTERPRISE_SEARCH_DOCUMENTS_DEFAULT_DOC_COUNT } = request.query; const from = page * size; - const searchResults: SearchResponseBody = await fetchSearchResults( client, - request.params.index_name, + indexName, '', from, size @@ -94,13 +94,14 @@ export function registerSearchRoute({ router, log }: RouteDependencies) { }, }, elasticsearchErrorHandler(log, async (context, request, response) => { + const indexName = decodeURIComponent(request.params.index_name); const { client } = (await context.core).elasticsearch; const { page = 0, size = ENTERPRISE_SEARCH_DOCUMENTS_DEFAULT_DOC_COUNT } = request.query; const from = page * size; const searchResults = await fetchSearchResults( client, - request.params.index_name, + indexName, request.params.query, from, size From 9a9f3017f6aaddb8be38469fbe7a85848fd7aad9 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Fri, 12 Aug 2022 09:42:53 +0100 Subject: [PATCH 38/59] [SecuritySolution] Apply the same sorting to kibana data view and sourcerer (#138534) * apply the same sorting to kibana data view and sourcerer * unit tests * Update x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.ts Co-authored-by: Steph Milovic * fix types error * lint Co-authored-by: Steph Milovic --- .../common/utils/sourcerer.test.ts | 20 +++++ .../common/utils/sourcerer.ts | 23 ++++++ .../components/sourcerer/index.test.tsx | 2 +- .../sourcerer/use_pick_index_patterns.tsx | 3 +- .../sourcerer/use_update_data_view.tsx | 2 +- .../common/containers/sourcerer/index.tsx | 7 +- .../common/store/sourcerer/helpers.test.ts | 7 +- .../public/common/store/sourcerer/helpers.ts | 19 +---- .../server/lib/sourcerer/routes/index.test.ts | 76 +++++++++++++++++++ .../server/lib/sourcerer/routes/index.ts | 8 +- 10 files changed, 134 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/utils/sourcerer.test.ts create mode 100644 x-pack/plugins/security_solution/common/utils/sourcerer.ts diff --git a/x-pack/plugins/security_solution/common/utils/sourcerer.test.ts b/x-pack/plugins/security_solution/common/utils/sourcerer.test.ts new file mode 100644 index 00000000000000..da75fefadc32d6 --- /dev/null +++ b/x-pack/plugins/security_solution/common/utils/sourcerer.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ensurePatternFormat } from './sourcerer'; + +describe('ensurePatternFormat', () => { + test('remove duplicate patterns', () => { + const result = ensurePatternFormat(['auditbeat-*', 'auditbeat-*']); + expect(result).toEqual(['auditbeat-*']); + }); + + test('sort patterns start with - at the back', () => { + const result = ensurePatternFormat(['-logs-*', 'auditbeat-*']); + expect(result).toEqual(['auditbeat-*', '-logs-*']); + }); +}); diff --git a/x-pack/plugins/security_solution/common/utils/sourcerer.ts b/x-pack/plugins/security_solution/common/utils/sourcerer.ts new file mode 100644 index 00000000000000..cb58c0ecf1e053 --- /dev/null +++ b/x-pack/plugins/security_solution/common/utils/sourcerer.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ +export const sortWithExcludesAtEnd = (indices: string[]) => { + const allSorted = indices.reduce( + (acc: { includes: string[]; excludes: string[] }, index) => + index.trim().startsWith('-') + ? { includes: acc.includes, excludes: [...acc.excludes, index] } + : { includes: [...acc.includes, index], excludes: acc.excludes }, + { includes: [], excludes: [] } + ); + return [...allSorted.includes.sort(), ...allSorted.excludes.sort()]; +}; + +export const ensurePatternFormat = (patternList: string[]): string[] => + sortWithExcludesAtEnd([ + ...new Set( + patternList.reduce((acc: string[], pattern: string) => [...pattern.split(','), ...acc], []) + ), + ]); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx index 19363d0a8bc946..497b3e4e439267 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/index.test.tsx @@ -13,7 +13,6 @@ import { cloneDeep } from 'lodash'; import { initialSourcererState, SourcererScopeName } from '../../store/sourcerer/model'; import { Sourcerer } from '.'; import { sourcererActions, sourcererModel } from '../../store/sourcerer'; -import { sortWithExcludesAtEnd } from '../../store/sourcerer/helpers'; import { createSecuritySolutionStorageMock, kibanaObservable, @@ -28,6 +27,7 @@ import { useSourcererDataView } from '../../containers/sourcerer'; import { useSignalHelpers } from '../../containers/sourcerer/use_signal_helpers'; import { TimelineId, TimelineType } from '../../../../common/types'; import { DEFAULT_INDEX_PATTERN } from '../../../../common/constants'; +import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; const mockDispatch = jest.fn(); diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx index 00f65211f1a01b..fd704f175a8522 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_pick_index_patterns.tsx @@ -10,10 +10,11 @@ import type { EuiComboBoxOptionOption, EuiSuperSelectOption } from '@elastic/eui import { useDispatch } from 'react-redux'; import { getSourcererDataView } from '../../containers/sourcerer/api'; -import { getScopePatternListSelection, sortWithExcludesAtEnd } from '../../store/sourcerer/helpers'; +import { getScopePatternListSelection } from '../../store/sourcerer/helpers'; import { sourcererActions, sourcererModel } from '../../store/sourcerer'; import { getDataViewSelectOptions, getPatternListWithoutSignals } from './helpers'; import { SourcererScopeName } from '../../store/sourcerer/model'; +import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; interface UsePickIndexPatternsProps { dataViewId: string | null; diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/use_update_data_view.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_update_data_view.tsx index 867c45e7a8e06c..100ad09cc60246 100644 --- a/x-pack/plugins/security_solution/public/common/components/sourcerer/use_update_data_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/use_update_data_view.tsx @@ -11,10 +11,10 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { useKibana } from '../../lib/kibana'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { ensurePatternFormat } from '../../store/sourcerer/helpers'; import * as i18n from './translations'; import { RefreshButton } from './refresh_button'; import { useAppToasts } from '../../hooks/use_app_toasts'; +import { ensurePatternFormat } from '../../../../common/utils/sourcerer'; export const useUpdateDataView = ( onOpenAndReset: () => void diff --git a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx index e799e9d608cd1a..effd5196dd9bcc 100644 --- a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx @@ -29,17 +29,14 @@ import { } from '../../../../common/constants'; import { TimelineId } from '../../../../common/types'; import { useDeepEqualSelector } from '../../hooks/use_selector'; -import { - checkIfIndicesExist, - getScopePatternListSelection, - sortWithExcludesAtEnd, -} from '../../store/sourcerer/helpers'; +import { checkIfIndicesExist, getScopePatternListSelection } from '../../store/sourcerer/helpers'; import { useAppToasts } from '../../hooks/use_app_toasts'; import { postSourcererDataView } from './api'; import { useDataView } from '../source/use_data_view'; import { useFetchIndex } from '../source'; import { useInitializeUrlParam, useUpdateUrlParam } from '../../utils/global_query_string'; import { URL_PARAM_KEY } from '../../hooks/use_url_state'; +import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; export const useInitSourcerer = ( scopeId: SourcererScopeName.default | SourcererScopeName.detections = SourcererScopeName.default diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.test.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.test.ts index 86302778c258a7..a1b9586834cf6a 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.test.ts @@ -7,11 +7,8 @@ import { mockGlobalState } from '../../mock'; import { SourcererScopeName } from './model'; -import { - getScopePatternListSelection, - sortWithExcludesAtEnd, - validateSelectedPatterns, -} from './helpers'; +import { getScopePatternListSelection, validateSelectedPatterns } from './helpers'; +import { sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; const signalIndexName = mockGlobalState.sourcerer.signalIndexName; diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts index db766c7e6b65d5..187e4923ed2181 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/helpers.ts @@ -10,17 +10,7 @@ import type { SourcererDataView, SourcererModel, SourcererScopeById } from './mo import { SourcererScopeName } from './model'; import type { SelectedDataViewPayload } from './actions'; import type { sourcererModel } from '../model'; - -export const sortWithExcludesAtEnd = (indices: string[]) => { - const allSorted = indices.reduce( - (acc: { includes: string[]; excludes: string[] }, index) => - index.trim().startsWith('-') - ? { includes: acc.includes, excludes: [...acc.excludes, index] } - : { includes: [...acc.includes, index], excludes: acc.excludes }, - { includes: [], excludes: [] } - ); - return [...allSorted.includes.sort(), ...allSorted.excludes.sort()]; -}; +import { ensurePatternFormat, sortWithExcludesAtEnd } from '../../../../common/utils/sourcerer'; export const getScopePatternListSelection = ( theDataView: SourcererDataView | undefined, @@ -46,13 +36,6 @@ export const getScopePatternListSelection = ( } }; -export const ensurePatternFormat = (patternList: string[]): string[] => - sortWithExcludesAtEnd([ - ...new Set( - patternList.reduce((acc: string[], pattern: string) => [...pattern.split(','), ...acc], []) - ), - ]); - export const validateSelectedPatterns = ( state: SourcererModel, payload: SelectedDataViewPayload, diff --git a/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.test.ts b/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.test.ts index 070a092a5b4d78..1125a0ce65428e 100644 --- a/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.test.ts @@ -180,6 +180,39 @@ describe('sourcerer route', () => { expect(response.body).toEqual(mockDataViewsTransformed); }); + test('passes sorted title on create and save', async () => { + const getMock = jest.fn(); + getMock.mockResolvedValueOnce(null); + getMock.mockResolvedValueOnce(mockPattern); + const mockCreateAndSave = jest.fn(); + const getStartServicesSpecial = jest.fn().mockResolvedValue([ + null, + { + data: { + indexPatterns: { + dataViewsServiceFactory: () => ({ + getIdsWithTitle: () => + new Promise((rs) => rs(mockDataViews.filter((v) => v.id !== mockPattern.id))), + get: getMock, + createAndSave: mockCreateAndSave.mockImplementation( + () => new Promise((rs) => rs(mockPattern)) + ), + updateSavedObject: () => new Promise((rs, rj) => rj(new Error('error'))), + }), + }, + }, + }, + ] as unknown) as StartServicesAccessor; + createSourcererDataViewRoute(server.router, getStartServicesSpecial); + await server.inject( + getSourcererRequest(['-elastic-logs-*', ...mockPatternList]), + requestContextMock.convertContext(context) + ); + expect(mockCreateAndSave.mock.calls[0][0].title).toEqual( + '.siem-signals-default,apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,ml_host_risk_score_*,packetbeat-*,traces-apm*,winlogbeat-*,-elastic-logs-*' + ); + }); + test('passes override=true on create and save', async () => { const getMock = jest.fn(); getMock.mockResolvedValueOnce(null); @@ -212,6 +245,49 @@ describe('sourcerer route', () => { expect(mockCreateAndSave.mock.calls[0][1]).toEqual(true); }); + test('passes sorted title on updateSavedObject', async () => { + const getMock = jest.fn(); + getMock.mockResolvedValueOnce(null); + getMock.mockResolvedValueOnce(mockPattern); + const mockCreateAndSave = jest.fn(); + const mockUpdateSavedObject = jest.fn(); + const getStartServicesSpecial = jest.fn().mockResolvedValue([ + null, + { + data: { + indexPatterns: { + dataViewsServiceFactory: () => ({ + getIdsWithTitle: () => + new Promise((rs) => + rs([{ id: 'security-solution', title: 'winlogbeat-*,-elastic-logs-*' }]) + ), + get: jest.fn().mockResolvedValue({ + id: 'security-solution', + title: 'winlogbeat-*,-elastic-logs-*', + }), + createAndSave: mockCreateAndSave.mockImplementation( + () => new Promise((rs) => rs(mockPattern)) + ), + updateSavedObject: mockUpdateSavedObject.mockImplementation( + () => new Promise((rs) => rs(mockPattern)) + ), + }), + }, + }, + }, + ] as unknown) as StartServicesAccessor; + createSourcererDataViewRoute(server.router, getStartServicesSpecial); + await server.inject( + getSourcererRequest(['-elastic-logs-*', ...mockPatternList]), + requestContextMock.convertContext(context) + ); + expect(mockUpdateSavedObject).toHaveBeenCalledWith({ + id: 'security-solution', + title: + '.siem-signals-default,apm-*-transaction*,auditbeat-*,endgame-*,filebeat-*,logs-*,ml_host_risk_score_*,packetbeat-*,traces-apm*,winlogbeat-*,-elastic-logs-*', + }); + }); + test('returns sourcerer formatted Data Views when SIEM Data View exists', async () => { createSourcererDataViewRoute(server.router, getStartServices); const response = await server.inject( diff --git a/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.ts b/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.ts index 24344b41ed2103..d959322a9720fb 100644 --- a/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.ts +++ b/x-pack/plugins/security_solution/server/lib/sourcerer/routes/index.ts @@ -16,6 +16,7 @@ import type { StartPlugins } from '../../../plugin'; import { buildSiemResponse } from '../../detection_engine/routes/utils'; import { findExistingIndices } from './helpers'; import { sourcererDataViewSchema, sourcererSchema } from './schema'; +import { ensurePatternFormat } from '../../../../common/utils/sourcerer'; export const createSourcererDataViewRoute = ( router: SecuritySolutionPluginRouter, @@ -58,8 +59,11 @@ export const createSourcererDataViewRoute = ( allDataViews.find((dv) => dv.id === dataViewId) ?? null; const { patternList } = request.body; - const patternListAsTitle = patternList.sort().join(); - const siemDataViewTitle = siemDataView ? siemDataView.title.split(',').sort().join() : ''; + const patternListAsTitle = ensurePatternFormat(patternList).join(); + const siemDataViewTitle = siemDataView + ? ensurePatternFormat(siemDataView.title.split(',')).join() + : ''; + if (siemDataView == null) { try { siemDataView = await dataViewService.createAndSave( From 7927826d6fe50f3b96f1be21d1366e38d9c2791c Mon Sep 17 00:00:00 2001 From: Dmitry Tomashevich <39378793+dimaanj@users.noreply.github.com> Date: Fri, 12 Aug 2022 12:04:26 +0300 Subject: [PATCH 39/59] [Discover] Update data view naming for locator (#138423) * [Discover] update data view naming for locator * [Discover] leave deprecated param * [Discover] add legacy param test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/discover/public/locator.test.ts | 22 ++++++++++++--------- src/plugins/discover/public/locator.ts | 7 +++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/plugins/discover/public/locator.test.ts b/src/plugins/discover/public/locator.test.ts index 98e0d7e853b61a..274e339c913436 100644 --- a/src/plugins/discover/public/locator.test.ts +++ b/src/plugins/discover/public/locator.test.ts @@ -57,9 +57,7 @@ describe('Discover url generator', () => { test('can specify specific data view', async () => { const { locator } = await setup(); - const { path } = await locator.getLocation({ - indexPatternId: dataViewId, - }); + const { path } = await locator.getLocation({ dataViewId }); const { _a, _g } = getStatesFromKbnUrl(path, ['_a', '_g']); expect(_a).toEqual({ @@ -224,13 +222,19 @@ describe('Discover url generator', () => { ); }); + test('should use legacy locator params', async () => { + const { locator } = await setup(); + const { path } = await locator.getLocation({ dataViewId }); + const { path: legacyParamsPath } = await locator.getLocation({ indexPatternId: dataViewId }); + + expect(path).toEqual(legacyParamsPath); + }); + describe('useHash property', () => { describe('when default useHash is set to false', () => { test('when using default, sets data view ID in the generated URL', async () => { const { locator } = await setup(); - const { path } = await locator.getLocation({ - indexPatternId: dataViewId, - }); + const { path } = await locator.getLocation({ dataViewId }); expect(path.indexOf(dataViewId) > -1).toBe(true); }); @@ -239,7 +243,7 @@ describe('Discover url generator', () => { const { locator } = await setup(); const { path } = await locator.getLocation({ useHash: true, - indexPatternId: dataViewId, + dataViewId, }); expect(path.indexOf(dataViewId) > -1).toBe(false); @@ -250,7 +254,7 @@ describe('Discover url generator', () => { test('when using default, does not set data view ID in the generated URL', async () => { const { locator } = await setup({ useHash: true }); const { path } = await locator.getLocation({ - indexPatternId: dataViewId, + dataViewId, }); expect(path.indexOf(dataViewId) > -1).toBe(false); @@ -260,7 +264,7 @@ describe('Discover url generator', () => { const { locator } = await setup({ useHash: true }); const { path } = await locator.getLocation({ useHash: false, - indexPatternId: dataViewId, + dataViewId, }); expect(path.indexOf(dataViewId) > -1).toBe(true); diff --git a/src/plugins/discover/public/locator.ts b/src/plugins/discover/public/locator.ts index b7ca5d78e4ab78..0fa2195cc246fc 100644 --- a/src/plugins/discover/public/locator.ts +++ b/src/plugins/discover/public/locator.ts @@ -24,6 +24,11 @@ export interface DiscoverAppLocatorParams extends SerializableRecord { /** * Optionally set index pattern / data view ID. */ + dataViewId?: string; + /** + * Duplication of dataViewId + * @deprecated + */ indexPatternId?: string; /** @@ -101,6 +106,7 @@ export class DiscoverAppLocatorDefinition implements LocatorDefinition !isFilterPinned(f)); if (indexPatternId) appState.index = indexPatternId; + if (dataViewId) appState.index = dataViewId; if (columns) appState.columns = columns; if (savedQuery) appState.savedQuery = savedQuery; if (sort) appState.sort = sort; From 945d456e71a85f5b55b2445f471260f8fbc07793 Mon Sep 17 00:00:00 2001 From: Mark Hopkin Date: Fri, 12 Aug 2022 10:19:04 +0100 Subject: [PATCH 40/59] Disable edit tag "save changes" button if no changes have been made (#138500) --- .../edition_modal/create_or_edit_modal.tsx | 16 ++++++--- .../functional/tests/edit.ts | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/saved_objects_tagging/public/components/edition_modal/create_or_edit_modal.tsx b/x-pack/plugins/saved_objects_tagging/public/components/edition_modal/create_or_edit_modal.tsx index da0338da3dca1b..ac4a2ac490b4df 100644 --- a/x-pack/plugins/saved_objects_tagging/public/components/edition_modal/create_or_edit_modal.tsx +++ b/x-pack/plugins/saved_objects_tagging/public/components/edition_modal/create_or_edit_modal.tsx @@ -58,10 +58,16 @@ export const CreateOrEditModal: FC = ({ const ifMounted = useIfMounted(); const [submitting, setSubmitting] = useState(false); - // we don't want this value to change when the user edit the name. + // we don't want this value to change when the user edits the tag // eslint-disable-next-line react-hooks/exhaustive-deps - const initialName = useMemo(() => tag.name, []); - + const initialTag = useMemo(() => tag, []); + const tagHasBeenModified = useMemo( + () => + tag.name !== initialTag.name || + tag.color !== initialTag.color || + tag.description !== initialTag.description, + [initialTag, tag] + ); const setName = useMemo(() => setField('name'), [setField]); const setColor = useMemo(() => setField('color'), [setField]); const setDescription = useMemo(() => setField('description'), [setField]); @@ -94,7 +100,7 @@ export const CreateOrEditModal: FC = ({ id="xpack.savedObjectsTagging.management.editModal.title" defaultMessage="Edit '{name}' tag" values={{ - name: initialName, + name: initialTag.name, }} /> ) : ( @@ -232,7 +238,7 @@ export const CreateOrEditModal: FC = ({ fill data-test-subj="createModalConfirmButton" onClick={onFormSubmit} - isDisabled={submitting} + isDisabled={submitting || (isEdit && !tagHasBeenModified)} > {isEdit ? ( { + const tag3Unmodified = { + name: 'tag-3', + description: 'Last but not least', + color: '#000000', + }; + it('should disable save button if no property is changed', async () => { + await tagModal.openEdit('tag-3'); + + await tagModal.fillForm(tag3Unmodified, { submit: false }); + expect(await tagModal.isConfirmDisabled()).to.be(true); + }); + it('should enable save button if name is changed', async () => { + await tagModal.openEdit('tag-3'); + + await tagModal.fillForm({ ...tag3Unmodified, name: 'changed name' }, { submit: false }); + expect(await tagModal.isConfirmDisabled()).to.be(false); + }); + it('should enable save button if description is changed', async () => { + await tagModal.openEdit('tag-3'); + + await tagModal.fillForm( + { ...tag3Unmodified, description: 'changed description' }, + { submit: false } + ); + expect(await tagModal.isConfirmDisabled()).to.be(false); + }); + it('should enable save button if color is changed', async () => { + await tagModal.openEdit('tag-3'); + + await tagModal.fillForm({ ...tag3Unmodified, color: '#FF0000' }, { submit: false }); + expect(await tagModal.isConfirmDisabled()).to.be(false); + }); + }); }); } From fcf3b8bb21f5b5f431141f7324d45d866c5dc740 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Fri, 12 Aug 2022 11:19:40 +0200 Subject: [PATCH 41/59] [Discover] Split saved searches out of discover plugin (#138388) --- .eslintrc.js | 2 +- .github/CODEOWNERS | 1 + .i18nrc.json | 1 + docs/developer/plugin-list.asciidoc | 4 +++ packages/kbn-optimizer/limits.yml | 1 + src/plugins/discover/kibana.json | 2 +- .../discover/public/__mocks__/saved_search.ts | 2 +- .../main/components/chart/discover_chart.tsx | 2 +- .../field_stats_table/field_stats_table.tsx | 2 +- .../components/layout/discover_documents.tsx | 2 +- .../components/layout/discover_layout.tsx | 2 +- .../main/components/layout/types.ts | 2 +- .../components/top_nav/get_top_nav_links.tsx | 2 +- .../components/top_nav/on_save_search.tsx | 2 +- .../application/main/discover_main_app.tsx | 3 +- .../application/main/discover_main_route.tsx | 2 +- .../main/hooks/use_discover_state.ts | 2 +- .../main/hooks/use_saved_search.ts | 2 +- .../main/hooks/use_search_session.ts | 2 +- .../main/services/discover_state.test.ts | 2 +- .../main/services/discover_state.ts | 2 +- .../application/main/utils/fetch_all.ts | 2 +- .../main/utils/get_state_defaults.ts | 2 +- .../main/utils/persist_saved_search.ts | 6 ++-- .../main/utils/update_search_source.test.ts | 2 +- .../main/utils/update_search_source.ts | 2 +- ...saved_search_url_conflict_callout.test.tsx | 2 +- .../saved_search_url_conflict_callout.ts | 4 +-- .../embeddable/saved_search_embeddable.tsx | 2 +- .../embeddable/search_embeddable_factory.ts | 8 ++--- .../discover/public/embeddable/types.ts | 2 +- .../utils/update_search_source.test.ts | 2 +- .../embeddable/view_saved_search_action.ts | 2 +- .../saved_search_alias_match_redirect.test.ts | 2 +- .../saved_search_alias_match_redirect.ts | 4 +-- src/plugins/discover/public/index.ts | 22 ++++++++----- .../discover/public/utils/breadcrumbs.ts | 2 +- .../discover/public/utils/get_sharing_data.ts | 2 +- src/plugins/discover/server/plugin.ts | 5 --- .../sample_data/register_sample_data.ts | 2 +- src/plugins/discover/tsconfig.json | 1 + src/plugins/saved_search/README.md | 3 ++ .../common}/index.ts | 0 .../common}/saved_searches_url.test.ts | 0 .../common}/saved_searches_url.ts | 0 src/plugins/saved_search/jest.config.js | 19 +++++++++++ src/plugins/saved_search/kibana.json | 16 +++++++++ src/plugins/saved_search/public/index.ts | 29 ++++++++++++++++ .../services/saved_searches/constants.ts | 0 .../saved_searches/get_saved_searches.test.ts | 0 .../saved_searches/get_saved_searches.ts | 0 .../public/services/saved_searches/index.ts | 2 -- .../save_saved_searches.test.ts | 0 .../saved_searches/save_saved_searches.ts | 0 .../saved_searches_utils.test.ts | 0 .../saved_searches/saved_searches_utils.ts | 7 ++-- .../public/services/saved_searches/types.ts | 15 +++++++-- src/plugins/saved_search/server/index.ts | 11 +++++++ src/plugins/saved_search/server/plugin.ts | 33 +++++++++++++++++++ .../server/saved_objects/index.ts | 0 .../server/saved_objects/search.ts | 0 .../saved_objects/search_migrations.test.ts | 0 .../server/saved_objects/search_migrations.ts | 0 src/plugins/saved_search/tsconfig.json | 21 ++++++++++++ src/plugins/visualizations/kibana.json | 2 +- src/plugins/visualizations/public/vis.ts | 2 +- .../public/visualize_app/types.ts | 2 +- .../utils/get_visualization_instance.test.ts | 4 +-- .../utils/get_visualization_instance.ts | 2 +- src/plugins/visualizations/tsconfig.json | 2 +- tsconfig.base.json | 2 ++ .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 74 files changed, 217 insertions(+), 76 deletions(-) rename src/plugins/discover/public/{services/saved_searches => components/saved_search_url_conflict_callout}/saved_search_url_conflict_callout.test.tsx (96%) rename src/plugins/discover/public/{services/saved_searches => components/saved_search_url_conflict_callout}/saved_search_url_conflict_callout.ts (93%) rename src/plugins/discover/public/{services/saved_searches => hooks}/saved_search_alias_match_redirect.test.ts (97%) rename src/plugins/discover/public/{services/saved_searches => hooks}/saved_search_alias_match_redirect.ts (93%) create mode 100644 src/plugins/saved_search/README.md rename src/plugins/{discover/common/services/saved_searches => saved_search/common}/index.ts (100%) rename src/plugins/{discover/common/services/saved_searches => saved_search/common}/saved_searches_url.test.ts (100%) rename src/plugins/{discover/common/services/saved_searches => saved_search/common}/saved_searches_url.ts (100%) create mode 100644 src/plugins/saved_search/jest.config.js create mode 100644 src/plugins/saved_search/kibana.json create mode 100644 src/plugins/saved_search/public/index.ts rename src/plugins/{discover => saved_search}/public/services/saved_searches/constants.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/get_saved_searches.test.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/get_saved_searches.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/index.ts (82%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/save_saved_searches.test.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/save_saved_searches.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/saved_searches_utils.test.ts (100%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/saved_searches_utils.ts (92%) rename src/plugins/{discover => saved_search}/public/services/saved_searches/types.ts (86%) create mode 100644 src/plugins/saved_search/server/index.ts create mode 100644 src/plugins/saved_search/server/plugin.ts rename src/plugins/{discover => saved_search}/server/saved_objects/index.ts (100%) rename src/plugins/{discover => saved_search}/server/saved_objects/search.ts (100%) rename src/plugins/{discover => saved_search}/server/saved_objects/search_migrations.test.ts (100%) rename src/plugins/{discover => saved_search}/server/saved_objects/search_migrations.ts (100%) create mode 100644 src/plugins/saved_search/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 372ddb85333596..603559f732a1c4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1341,7 +1341,7 @@ module.exports = { * Discover overrides */ { - files: ['src/plugins/discover/**/*.{ts,tsx}'], + files: ['src/plugins/discover/**/*.{ts,tsx}', 'src/plugins/saved_search/**/*.{ts,tsx}'], rules: { '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/ban-ts-comment': [ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 19d2f1cdb27ef1..09484706c05e0d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,6 +10,7 @@ # Data Discovery /src/plugins/discover/ @elastic/kibana-data-discovery +/src/plugins/saved_search/ @elastic/kibana-data-discovery /x-pack/plugins/discover_enhanced/ @elastic/kibana-data-discovery /test/functional/apps/discover/ @elastic/kibana-data-discovery /x-pack/plugins/graph/ @elastic/kibana-data-discovery diff --git a/.i18nrc.json b/.i18nrc.json index b77d2c42508f1b..cee83a60c1fd2c 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -18,6 +18,7 @@ "dataViews": "src/plugins/data_views", "devTools": "src/plugins/dev_tools", "discover": "src/plugins/discover", + "savedSearch": "src/plugins/saved_search", "embeddableApi": "src/plugins/embeddable", "embeddableExamples": "examples/embeddable_examples", "esQuery": "packages/kbn-es-query/src", diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 10bd6fbba96ce6..64077b2ecc106f 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -246,6 +246,10 @@ Content is fetched from the remote (https://feeds.elastic.co) once a day, with p oss plugins. +|{kib-repo}blob/{branch}/src/plugins/saved_search/README.md[savedSearch] +|Contains the saved search saved object definition and helpers. + + |{kib-repo}blob/{branch}/src/plugins/screenshot_mode/README.md[screenshotMode] |The service exposed by this plugin informs consumers whether they should optimize for non-interactivity. In this way plugins can avoid loading unnecessary code, data or other services. diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index c12c3081a737e6..2a116d9ab60ed1 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -120,6 +120,7 @@ pageLoadAssetSize: controls: 40000 expressionPartitionVis: 26338 sharedUX: 16225 + savedSearch: 16225 ux: 20784 sessionView: 77750 cloudSecurityPosture: 19109 diff --git a/src/plugins/discover/kibana.json b/src/plugins/discover/kibana.json index 7c8376795863af..78e5265bcb3ac7 100644 --- a/src/plugins/discover/kibana.json +++ b/src/plugins/discover/kibana.json @@ -18,7 +18,7 @@ "expressions" ], "optionalPlugins": ["home", "share", "usageCollection", "spaces", "triggersActionsUi"], - "requiredBundles": ["kibanaUtils", "kibanaReact", "dataViews", "unifiedSearch"], + "requiredBundles": ["kibanaUtils", "kibanaReact", "dataViews", "unifiedSearch", "savedSearch"], "extraPublicDirs": ["common"], "owner": { "name": "Data Discovery", diff --git a/src/plugins/discover/public/__mocks__/saved_search.ts b/src/plugins/discover/public/__mocks__/saved_search.ts index 8cd6fbd5b95724..1f430de118317f 100644 --- a/src/plugins/discover/public/__mocks__/saved_search.ts +++ b/src/plugins/discover/public/__mocks__/saved_search.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { SavedSearch } from '../services/saved_searches'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks'; import { dataViewMock } from './data_view'; import { dataViewWithTimefieldMock } from './data_view_with_timefield'; diff --git a/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx b/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx index becf20bff3cb2e..2b50856fa84fc6 100644 --- a/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx +++ b/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx @@ -18,8 +18,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { HitsCounter } from '../hits_counter'; -import { SavedSearch } from '../../../../services/saved_searches'; import { GetStateReturn } from '../../services/discover_state'; import { DiscoverHistogram } from './histogram'; import { DataCharts$, DataTotalHits$ } from '../../hooks/use_saved_search'; diff --git a/src/plugins/discover/public/application/main/components/field_stats_table/field_stats_table.tsx b/src/plugins/discover/public/application/main/components/field_stats_table/field_stats_table.tsx index 8334e0ec74257e..59d8fae4afbeb5 100644 --- a/src/plugins/discover/public/application/main/components/field_stats_table/field_stats_table.tsx +++ b/src/plugins/discover/public/application/main/components/field_stats_table/field_stats_table.tsx @@ -17,9 +17,9 @@ import { IEmbeddable, isErrorEmbeddable, } from '@kbn/embeddable-plugin/public'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { FIELD_STATISTICS_LOADED } from './constants'; -import type { SavedSearch } from '../../../../services/saved_searches'; import type { GetStateReturn } from '../../services/discover_state'; import { AvailableFields$, DataRefetch$ } from '../../hooks/use_saved_search'; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx index 2a824ddf361fb1..92443cea9f1aed 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx @@ -15,6 +15,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataView } from '@kbn/data-views-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { DocViewFilterFn } from '../../../../services/doc_views/doc_views_types'; import { DiscoverGrid } from '../../../../components/discover_grid/discover_grid'; @@ -27,7 +28,6 @@ import { HIDE_ANNOUNCEMENTS, } from '../../../../../common'; import { useColumns } from '../../../../hooks/use_data_grid_columns'; -import { SavedSearch } from '../../../../services/saved_searches'; import { DataDocuments$, DataDocumentsMsg, RecordRawType } from '../../hooks/use_saved_search'; import { AppState, GetStateReturn } from '../../services/discover_state'; import { useDataState } from '../../hooks/use_data_state'; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 1f353bdaeba286..4806e8f35a007c 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -42,12 +42,12 @@ import { useColumns } from '../../../../hooks/use_data_grid_columns'; import { DiscoverDocuments } from './discover_documents'; import { FetchStatus } from '../../../types'; import { useDataState } from '../../hooks/use_data_state'; -import { SavedSearchURLConflictCallout } from '../../../../services/saved_searches'; import { FieldStatisticsTable } from '../field_stats_table'; import { VIEW_MODE } from '../../../../components/view_mode_toggle'; import { DOCUMENTS_VIEW_CLICK, FIELD_STATISTICS_VIEW_CLICK } from '../field_stats_table/constants'; import { hasActiveFilter } from './utils'; import { getRawRecordType } from '../../utils/get_raw_record_type'; +import { SavedSearchURLConflictCallout } from '../../../../components/saved_search_url_conflict_callout/saved_search_url_conflict_callout'; /** * Local storage key for sidebar persistence state diff --git a/src/plugins/discover/public/application/main/components/layout/types.ts b/src/plugins/discover/public/application/main/components/layout/types.ts index 41e3e9d8b7718a..e254dd8774a37a 100644 --- a/src/plugins/discover/public/application/main/components/layout/types.ts +++ b/src/plugins/discover/public/application/main/components/layout/types.ts @@ -11,10 +11,10 @@ import type { SavedObject } from '@kbn/data-plugin/public'; import type { DataView, DataViewAttributes } from '@kbn/data-views-plugin/public'; import { ISearchSource } from '@kbn/data-plugin/public'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { DataTableRecord } from '../../../../types'; import { AppState, GetStateReturn } from '../../services/discover_state'; import { DataRefetch$, SavedSearchData } from '../../hooks/use_saved_search'; -import { SavedSearch } from '../../../../services/saved_searches'; export interface DiscoverLayoutProps { dataView: DataView; diff --git a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx index 39f842b58250cd..5ce9f15ce43d9d 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx @@ -11,10 +11,10 @@ import type { ISearchSource } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { unhashUrl } from '@kbn/kibana-utils-plugin/public'; import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { showOpenSearchPanel } from './show_open_search_panel'; import { getSharingData, showPublicUrlSwitch } from '../../../../utils/get_sharing_data'; import { DiscoverServices } from '../../../../build_services'; -import { SavedSearch } from '../../../../services/saved_searches'; import { onSaveSearch } from './on_save_search'; import { GetStateReturn } from '../../services/discover_state'; import { openOptionsPopover } from './open_options_popover'; diff --git a/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx b/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx index 6491da5bd8baa0..9f0c1f9552f2ce 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { SavedObjectSaveModal, showSaveModal, OnSaveProps } from '@kbn/saved-objects-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; -import { SavedSearch, SaveSavedSearchOptions } from '../../../../services/saved_searches'; +import { SavedSearch, SaveSavedSearchOptions } from '@kbn/saved-search-plugin/public'; import { DiscoverServices } from '../../../../build_services'; import { GetStateReturn } from '../../services/discover_state'; import { setBreadcrumbsTitle } from '../../../../utils/breadcrumbs'; diff --git a/src/plugins/discover/public/application/main/discover_main_app.tsx b/src/plugins/discover/public/application/main/discover_main_app.tsx index 21e709a7d1cc10..9b48be3ad1bc81 100644 --- a/src/plugins/discover/public/application/main/discover_main_app.tsx +++ b/src/plugins/discover/public/application/main/discover_main_app.tsx @@ -9,14 +9,15 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; import type { DataViewAttributes } from '@kbn/data-views-plugin/public'; import type { SavedObject } from '@kbn/data-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { DiscoverLayout } from './components/layout'; import { setBreadcrumbsTitle } from '../../utils/breadcrumbs'; import { addHelpMenuToAppChrome } from '../../components/help_menu/help_menu_util'; import { useDiscoverState } from './hooks/use_discover_state'; import { useUrl } from './hooks/use_url'; -import { SavedSearch, useSavedSearchAliasMatchRedirect } from '../../services/saved_searches'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { DataTableRecord } from '../../types'; +import { useSavedSearchAliasMatchRedirect } from '../../hooks/saved_search_alias_match_redirect'; const DiscoverLayoutMemoized = React.memo(DiscoverLayout); diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx index 773eac7a556edf..cec20f64d82b28 100644 --- a/src/plugins/discover/public/application/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/main/discover_main_route.tsx @@ -23,7 +23,7 @@ import { SavedSearch, getSavedSearch, getSavedSearchFullPathUrl, -} from '../../services/saved_searches'; +} from '@kbn/saved-search-plugin/public'; import { getState } from './services/discover_state'; import { loadDataView, resolveDataView } from './utils/resolve_data_view'; import { DiscoverMainApp } from './discover_main_app'; diff --git a/src/plugins/discover/public/application/main/hooks/use_discover_state.ts b/src/plugins/discover/public/application/main/hooks/use_discover_state.ts index 9d464d5267f60c..b5cf634ebe3a08 100644 --- a/src/plugins/discover/public/application/main/hooks/use_discover_state.ts +++ b/src/plugins/discover/public/application/main/hooks/use_discover_state.ts @@ -16,10 +16,10 @@ import { AggregateQuery, Query, } from '@kbn/es-query'; +import { SavedSearch, getSavedSearch } from '@kbn/saved-search-plugin/public'; import { getState } from '../services/discover_state'; import { getStateDefaults } from '../utils/get_state_defaults'; import { DiscoverServices } from '../../../build_services'; -import { SavedSearch, getSavedSearch } from '../../../services/saved_searches'; import { loadDataView } from '../utils/resolve_data_view'; import { useSavedSearch as useSavedSearchData, DataDocumentsMsg } from './use_saved_search'; import { diff --git a/src/plugins/discover/public/application/main/hooks/use_saved_search.ts b/src/plugins/discover/public/application/main/hooks/use_saved_search.ts index def74bd94e7b1b..3b9948f88d17e3 100644 --- a/src/plugins/discover/public/application/main/hooks/use_saved_search.ts +++ b/src/plugins/discover/public/application/main/hooks/use_saved_search.ts @@ -10,6 +10,7 @@ import { BehaviorSubject, Subject } from 'rxjs'; import type { AutoRefreshDoneFn } from '@kbn/data-plugin/public'; import { ISearchSource } from '@kbn/data-plugin/public'; import { RequestAdapter } from '@kbn/inspector-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { getRawRecordType } from '../utils/get_raw_record_type'; import { DiscoverServices } from '../../../build_services'; import { DiscoverSearchSessionManager } from '../services/discover_search_session'; @@ -22,7 +23,6 @@ import { fetchAll } from '../utils/fetch_all'; import { useBehaviorSubject } from './use_behavior_subject'; import { sendResetMsg } from './use_saved_search_messages'; import { getFetch$ } from '../utils/get_fetch_observable'; -import { SavedSearch } from '../../../services/saved_searches'; import type { DataTableRecord } from '../../../types'; export interface SavedSearchData { diff --git a/src/plugins/discover/public/application/main/hooks/use_search_session.ts b/src/plugins/discover/public/application/main/hooks/use_search_session.ts index 1bdbc27968f73f..af5768d7c47525 100644 --- a/src/plugins/discover/public/application/main/hooks/use_search_session.ts +++ b/src/plugins/discover/public/application/main/hooks/use_search_session.ts @@ -8,13 +8,13 @@ import { useMemo, useEffect } from 'react'; import { History } from 'history'; import { noSearchSessionStorageCapabilityMessage } from '@kbn/data-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { DiscoverSearchSessionManager } from '../services/discover_search_session'; import { createSearchSessionRestorationDataProvider, GetStateReturn, } from '../services/discover_state'; import { DiscoverServices } from '../../../build_services'; -import { SavedSearch } from '../../../services/saved_searches'; export function useSearchSession({ services, diff --git a/src/plugins/discover/public/application/main/services/discover_state.test.ts b/src/plugins/discover/public/application/main/services/discover_state.test.ts index 5ae2da5149d69c..ccec7582ce8d33 100644 --- a/src/plugins/discover/public/application/main/services/discover_state.test.ts +++ b/src/plugins/discover/public/application/main/services/discover_state.test.ts @@ -14,7 +14,7 @@ import { } from './discover_state'; import { createBrowserHistory, History } from 'history'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; -import type { SavedSearch } from '../../../services/saved_searches'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import { SEARCH_FIELDS_FROM_SOURCE } from '../../../../common'; let history: History; diff --git a/src/plugins/discover/public/application/main/services/discover_state.ts b/src/plugins/discover/public/application/main/services/discover_state.ts index 847462510cebad..33393eeecdd758 100644 --- a/src/plugins/discover/public/application/main/services/discover_state.ts +++ b/src/plugins/discover/public/application/main/services/discover_state.ts @@ -36,8 +36,8 @@ import { syncQueryStateWithUrl, } from '@kbn/data-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { DiscoverGridSettings } from '../../../components/discover_grid/types'; -import { SavedSearch } from '../../../services/saved_searches'; import { handleSourceColumnState } from '../../../utils/state_helpers'; import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '../../../locator'; import { VIEW_MODE } from '../../../components/view_mode_toggle'; diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.ts b/src/plugins/discover/public/application/main/utils/fetch_all.ts index 30d860f7fa6693..42b415630e92c5 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.ts @@ -9,6 +9,7 @@ import { DataPublicPluginStart, ISearchSource } from '@kbn/data-plugin/public'; import { Adapters } from '@kbn/inspector-plugin/common'; import { ReduxLikeStateContainer } from '@kbn/kibana-utils-plugin/common'; import { DataViewType } from '@kbn/data-views-plugin/public'; +import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public'; import { getRawRecordType } from './get_raw_record_type'; import { sendCompleteMsg, @@ -19,7 +20,6 @@ import { sendResetMsg, } from '../hooks/use_saved_search_messages'; import { updateSearchSource } from './update_search_source'; -import type { SavedSearch, SortOrder } from '../../../services/saved_searches'; import { fetchDocuments } from './fetch_documents'; import { fetchTotalHits } from './fetch_total_hits'; import { fetchChart } from './fetch_chart'; diff --git a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts index 56996e999d6c98..5eb863372d90ce 100644 --- a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts +++ b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts @@ -10,13 +10,13 @@ import { cloneDeep, isEqual } from 'lodash'; import { IUiSettingsClient } from '@kbn/core/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { DEFAULT_COLUMNS_SETTING, DOC_HIDE_TIME_COLUMN_SETTING, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, } from '../../../../common'; -import { SavedSearch } from '../../../services/saved_searches'; import { AppState } from '../services/discover_state'; import { getDefaultSort, getSortArray } from '../../../components/doc_table'; diff --git a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts index ac5554028d2e8e..691a8a6604194b 100644 --- a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts +++ b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts @@ -8,12 +8,12 @@ import { isOfAggregateQueryType } from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/public'; import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; +import { saveSavedSearch } from '@kbn/saved-search-plugin/public'; import { updateSearchSource } from './update_search_source'; -import { SavedSearch } from '../../../services/saved_searches'; import { AppState } from '../services/discover_state'; -import type { SortOrder } from '../../../services/saved_searches'; import { DiscoverServices } from '../../../build_services'; -import { saveSavedSearch } from '../../../services/saved_searches'; /** * Helper function to update and persist the given savedSearch */ diff --git a/src/plugins/discover/public/application/main/utils/update_search_source.test.ts b/src/plugins/discover/public/application/main/utils/update_search_source.test.ts index 7e3029f02fac02..5ab1dd962652f9 100644 --- a/src/plugins/discover/public/application/main/utils/update_search_source.test.ts +++ b/src/plugins/discover/public/application/main/utils/update_search_source.test.ts @@ -9,7 +9,7 @@ import { updateSearchSource } from './update_search_source'; import { createSearchSourceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import { dataViewMock } from '../../../__mocks__/data_view'; -import type { SortOrder } from '../../../services/saved_searches'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { discoverServiceMock } from '../../../__mocks__/services'; describe('updateSearchSource', () => { diff --git a/src/plugins/discover/public/application/main/utils/update_search_source.ts b/src/plugins/discover/public/application/main/utils/update_search_source.ts index 3890924519fe1c..aea864af91d816 100644 --- a/src/plugins/discover/public/application/main/utils/update_search_source.ts +++ b/src/plugins/discover/public/application/main/utils/update_search_source.ts @@ -8,8 +8,8 @@ import { ISearchSource } from '@kbn/data-plugin/public'; import { DataViewType, DataView } from '@kbn/data-views-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { SORT_DEFAULT_ORDER_SETTING } from '../../../../common'; -import type { SortOrder } from '../../../services/saved_searches'; import { DiscoverServices } from '../../../build_services'; import { getSortForSearchSource } from '../../../components/doc_table'; diff --git a/src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.test.tsx b/src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.test.tsx similarity index 96% rename from src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.test.tsx rename to src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.test.tsx index 0d2fd18a6afc73..d65bc83befa967 100644 --- a/src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.test.tsx +++ b/src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.test.tsx @@ -11,9 +11,9 @@ import type { History } from 'history'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { SavedSearchURLConflictCallout } from './saved_search_url_conflict_callout'; -import type { SavedSearch } from './types'; import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; describe('SavedSearchURLConflictCallout', () => { let spaces: ReturnType; diff --git a/src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.ts b/src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.ts similarity index 93% rename from src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.ts rename to src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.ts index 3da3fc346ffaa8..1fbb74d6130cbe 100644 --- a/src/plugins/discover/public/services/saved_searches/saved_search_url_conflict_callout.ts +++ b/src/plugins/discover/public/components/saved_search_url_conflict_callout/saved_search_url_conflict_callout.ts @@ -9,9 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { History } from 'history'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; -import { getSavedSearchUrl } from './saved_searches_utils'; - -import type { SavedSearch } from './types'; +import { getSavedSearchUrl, SavedSearch } from '@kbn/saved-search-plugin/public'; interface SavedSearchURLConflictCalloutProps { savedSearch?: SavedSearch; diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx index 1fb7acc18b7db3..b4c3f41e4ba36f 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx @@ -32,11 +32,11 @@ import { ISearchSource } from '@kbn/data-plugin/public'; import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { RecordRawType } from '../application/main/hooks/use_saved_search'; import { buildDataTableRecord } from '../utils/build_data_record'; import { DataTableRecord, EsHitRecord } from '../types'; import { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; -import { SavedSearch } from '../services/saved_searches'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; import { DiscoverServices } from '../build_services'; import { SavedSearchEmbeddableComponent } from './saved_search_embeddable_component'; diff --git a/src/plugins/discover/public/embeddable/search_embeddable_factory.ts b/src/plugins/discover/public/embeddable/search_embeddable_factory.ts index e43769bb8c3838..331fa7103a8258 100644 --- a/src/plugins/discover/public/embeddable/search_embeddable_factory.ts +++ b/src/plugins/discover/public/embeddable/search_embeddable_factory.ts @@ -16,14 +16,14 @@ import { import type { TimeRange } from '@kbn/es-query'; -import { SearchInput, SearchOutput } from './types'; -import { SEARCH_EMBEDDABLE_TYPE } from './constants'; -import { SavedSearchEmbeddable } from './saved_search_embeddable'; import { getSavedSearch, getSavedSearchUrl, throwErrorOnSavedSearchUrlConflict, -} from '../services/saved_searches'; +} from '@kbn/saved-search-plugin/public'; +import { SearchInput, SearchOutput } from './types'; +import { SEARCH_EMBEDDABLE_TYPE } from './constants'; +import { SavedSearchEmbeddable } from './saved_search_embeddable'; import { DiscoverServices } from '../build_services'; interface StartServices { diff --git a/src/plugins/discover/public/embeddable/types.ts b/src/plugins/discover/public/embeddable/types.ts index a72d7d86f6801e..dacb9b7d81d437 100644 --- a/src/plugins/discover/public/embeddable/types.ts +++ b/src/plugins/discover/public/embeddable/types.ts @@ -14,7 +14,7 @@ import { } from '@kbn/embeddable-plugin/public'; import type { Filter, TimeRange, Query } from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/public'; -import { SavedSearch } from '../services/saved_searches'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { SortOrder } from '../components/doc_table/components/table_header/helpers'; export interface SearchInput extends EmbeddableInput { diff --git a/src/plugins/discover/public/embeddable/utils/update_search_source.test.ts b/src/plugins/discover/public/embeddable/utils/update_search_source.test.ts index 00e0175f813c2d..779fcfffde7788 100644 --- a/src/plugins/discover/public/embeddable/utils/update_search_source.test.ts +++ b/src/plugins/discover/public/embeddable/utils/update_search_source.test.ts @@ -8,7 +8,7 @@ import { createSearchSourceMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import { updateSearchSource } from './update_search_source'; import { dataViewMock } from '../../__mocks__/data_view'; -import type { SortOrder } from '../../services/saved_searches'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; describe('updateSearchSource', () => { const defaults = { diff --git a/src/plugins/discover/public/embeddable/view_saved_search_action.ts b/src/plugins/discover/public/embeddable/view_saved_search_action.ts index 59e27de85c2bd9..1b584893364233 100644 --- a/src/plugins/discover/public/embeddable/view_saved_search_action.ts +++ b/src/plugins/discover/public/embeddable/view_saved_search_action.ts @@ -10,9 +10,9 @@ import { ApplicationStart } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { IEmbeddable, ViewMode } from '@kbn/embeddable-plugin/public'; import { Action } from '@kbn/ui-actions-plugin/public'; +import { getSavedSearchUrl } from '@kbn/saved-search-plugin/public'; import { SavedSearchEmbeddable } from './saved_search_embeddable'; import { SEARCH_EMBEDDABLE_TYPE } from '../../common'; -import { getSavedSearchUrl } from '../services/saved_searches'; export const ACTION_VIEW_SAVED_SEARCH = 'ACTION_VIEW_SAVED_SEARCH'; diff --git a/src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.test.ts b/src/plugins/discover/public/hooks/saved_search_alias_match_redirect.test.ts similarity index 97% rename from src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.test.ts rename to src/plugins/discover/public/hooks/saved_search_alias_match_redirect.test.ts index 62c2e447f6d8ba..93f2c1be1ab6bd 100644 --- a/src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.test.ts +++ b/src/plugins/discover/public/hooks/saved_search_alias_match_redirect.test.ts @@ -10,7 +10,7 @@ import { renderHook } from '@testing-library/react-hooks'; import type { History } from 'history'; import { useSavedSearchAliasMatchRedirect } from './saved_search_alias_match_redirect'; -import type { SavedSearch } from './types'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; diff --git a/src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.ts b/src/plugins/discover/public/hooks/saved_search_alias_match_redirect.ts similarity index 93% rename from src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.ts rename to src/plugins/discover/public/hooks/saved_search_alias_match_redirect.ts index e395ccbdaf264e..983701236e59bf 100644 --- a/src/plugins/discover/public/services/saved_searches/saved_search_alias_match_redirect.ts +++ b/src/plugins/discover/public/hooks/saved_search_alias_match_redirect.ts @@ -10,9 +10,7 @@ import type { History } from 'history'; import { useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; -import { getSavedSearchUrl } from './saved_searches_utils'; - -import type { SavedSearch } from './types'; +import { getSavedSearchUrl, SavedSearch } from '@kbn/saved-search-plugin/public'; interface SavedSearchAliasMatchRedirectProps { savedSearch?: SavedSearch; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index 936efb7239313f..b516161d0e97bc 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -9,15 +9,6 @@ import { PluginInitializerContext } from '@kbn/core/public'; import { DiscoverPlugin } from './plugin'; -export type { SavedSearch } from './services/saved_searches'; -export { - getSavedSearch, - getSavedSearchFullPathUrl, - getSavedSearchUrl, - getSavedSearchUrlConflictMessage, - throwErrorOnSavedSearchUrlConflict, -} from './services/saved_searches'; - export type { DiscoverSetup, DiscoverStart } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new DiscoverPlugin(initializerContext); @@ -29,3 +20,16 @@ export { loadSharingDataHelpers } from './utils'; export { DISCOVER_APP_LOCATOR } from './locator'; export type { DiscoverAppLocator, DiscoverAppLocatorParams } from './locator'; + +// re-export types and static functions to give other plugins time to migrate away +export { + SavedSearch, + getSavedSearch, + getSavedSearchFullPathUrl, + getSavedSearchUrl, + getSavedSearchUrlConflictMessage, + throwErrorOnSavedSearchUrlConflict, + VIEW_MODE, + DiscoverGridSettings, + DiscoverGridSettingsColumn, +} from '@kbn/saved-search-plugin/public'; diff --git a/src/plugins/discover/public/utils/breadcrumbs.ts b/src/plugins/discover/public/utils/breadcrumbs.ts index e89186fc6f38d4..ca968b43fdb2a8 100644 --- a/src/plugins/discover/public/utils/breadcrumbs.ts +++ b/src/plugins/discover/public/utils/breadcrumbs.ts @@ -8,7 +8,7 @@ import { ChromeStart } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { SavedSearch } from '../services/saved_searches'; +import { SavedSearch } from '@kbn/saved-search-plugin/public'; export function getRootBreadcrumbs(breadcrumb?: string) { return [ diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index 66a6a6f1eed107..6d99edd3d9fe1d 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -14,12 +14,12 @@ import type { SerializedSearchSourceFields, } from '@kbn/data-plugin/public'; import type { Filter } from '@kbn/es-query'; +import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public'; import { DOC_HIDE_TIME_COLUMN_SETTING, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, } from '../../common'; -import type { SavedSearch, SortOrder } from '../services/saved_searches'; import { getSortForSearchSource } from '../components/doc_table'; import { AppState, isEqualFilters } from '../application/main/services/discover_state'; diff --git a/src/plugins/discover/server/plugin.ts b/src/plugins/discover/server/plugin.ts index 888fcf55c23516..cfd62312fb6da1 100644 --- a/src/plugins/discover/server/plugin.ts +++ b/src/plugins/discover/server/plugin.ts @@ -11,7 +11,6 @@ import type { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { getUiSettings } from './ui_settings'; import { capabilitiesProvider } from './capabilities_provider'; -import { getSavedSearchObjectType } from './saved_objects'; import { registerSampleData } from './sample_data'; export class DiscoverServerPlugin implements Plugin { @@ -22,12 +21,8 @@ export class DiscoverServerPlugin implements Plugin { home?: HomeServerPluginSetup; } ) { - const getSearchSourceMigrations = plugins.data.search.searchSource.getAllMigrations.bind( - plugins.data.search.searchSource - ); core.capabilities.registerProvider(capabilitiesProvider); core.uiSettings.register(getUiSettings(core.docLinks)); - core.savedObjects.registerType(getSavedSearchObjectType(getSearchSourceMigrations)); if (plugins.home) { registerSampleData(plugins.home.sampleData); diff --git a/src/plugins/discover/server/sample_data/register_sample_data.ts b/src/plugins/discover/server/sample_data/register_sample_data.ts index a1ff9951d9179d..a864045a5b2b7a 100644 --- a/src/plugins/discover/server/sample_data/register_sample_data.ts +++ b/src/plugins/discover/server/sample_data/register_sample_data.ts @@ -8,8 +8,8 @@ import { i18n } from '@kbn/i18n'; import type { SampleDataRegistrySetup } from '@kbn/home-plugin/server'; +import { getSavedSearchFullPathUrl } from '@kbn/saved-search-plugin/common'; import { APP_ICON } from '../../common'; -import { getSavedSearchFullPathUrl } from '../../common/services/saved_searches'; function getDiscoverPathForSampleDataset(objId: string) { // TODO: remove the time range from the URL query when saved search objects start supporting time range configuration diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 5cdc21844c8a19..efadcc88443a14 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -10,6 +10,7 @@ "references": [ { "path": "../../core/tsconfig.json" }, { "path": "../charts/tsconfig.json" }, + { "path": "../saved_search/tsconfig.json" }, { "path": "../data/tsconfig.json" }, { "path": "../expressions/tsconfig.json" }, { "path": "../embeddable/tsconfig.json" }, diff --git a/src/plugins/saved_search/README.md b/src/plugins/saved_search/README.md new file mode 100644 index 00000000000000..d2234f04494a1e --- /dev/null +++ b/src/plugins/saved_search/README.md @@ -0,0 +1,3 @@ +# Saved search + +Contains the saved search saved object definition and helpers. diff --git a/src/plugins/discover/common/services/saved_searches/index.ts b/src/plugins/saved_search/common/index.ts similarity index 100% rename from src/plugins/discover/common/services/saved_searches/index.ts rename to src/plugins/saved_search/common/index.ts diff --git a/src/plugins/discover/common/services/saved_searches/saved_searches_url.test.ts b/src/plugins/saved_search/common/saved_searches_url.test.ts similarity index 100% rename from src/plugins/discover/common/services/saved_searches/saved_searches_url.test.ts rename to src/plugins/saved_search/common/saved_searches_url.test.ts diff --git a/src/plugins/discover/common/services/saved_searches/saved_searches_url.ts b/src/plugins/saved_search/common/saved_searches_url.ts similarity index 100% rename from src/plugins/discover/common/services/saved_searches/saved_searches_url.ts rename to src/plugins/saved_search/common/saved_searches_url.ts diff --git a/src/plugins/saved_search/jest.config.js b/src/plugins/saved_search/jest.config.js new file mode 100644 index 00000000000000..849af79d37911d --- /dev/null +++ b/src/plugins/saved_search/jest.config.js @@ -0,0 +1,19 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['/src/plugins/saved_search'], + testRunner: 'jasmine2', + coverageDirectory: '/target/kibana-coverage/jest/src/plugins/saved_search', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/src/plugins/saved_search/{common,public,server}/**/*.{js,ts,tsx}', + ], +}; diff --git a/src/plugins/saved_search/kibana.json b/src/plugins/saved_search/kibana.json new file mode 100644 index 00000000000000..d58d429474c879 --- /dev/null +++ b/src/plugins/saved_search/kibana.json @@ -0,0 +1,16 @@ +{ + "id": "savedSearch", + "version": "kibana", + "server": true, + "ui": true, + "requiredPlugins": [ + "data" + ], + "requiredBundles": ["kibanaUtils"], + "extraPublicDirs": ["common"], + "owner": { + "name": "Data Discovery", + "githubTeam": "kibana-data-discovery" + }, + "description": "This plugin contains the definition and helper methods around saved searches, used by discover and visualizations." +} diff --git a/src/plugins/saved_search/public/index.ts b/src/plugins/saved_search/public/index.ts new file mode 100644 index 00000000000000..047d663b16caa9 --- /dev/null +++ b/src/plugins/saved_search/public/index.ts @@ -0,0 +1,29 @@ +/* + * 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 type { SavedSearch, SaveSavedSearchOptions, SortOrder } from './services/saved_searches'; +export { + getSavedSearch, + getSavedSearchFullPathUrl, + getSavedSearchUrl, + getSavedSearchUrlConflictMessage, + throwErrorOnSavedSearchUrlConflict, + saveSavedSearch, +} from './services/saved_searches'; +export type { + DiscoverGridSettings, + DiscoverGridSettingsColumn, +} from './services/saved_searches/types'; +export { VIEW_MODE } from './services/saved_searches/types'; + +export function plugin() { + return { + setup: () => {}, + start: () => {}, + }; +} diff --git a/src/plugins/discover/public/services/saved_searches/constants.ts b/src/plugins/saved_search/public/services/saved_searches/constants.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/constants.ts rename to src/plugins/saved_search/public/services/saved_searches/constants.ts diff --git a/src/plugins/discover/public/services/saved_searches/get_saved_searches.test.ts b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/get_saved_searches.test.ts rename to src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts diff --git a/src/plugins/discover/public/services/saved_searches/get_saved_searches.ts b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/get_saved_searches.ts rename to src/plugins/saved_search/public/services/saved_searches/get_saved_searches.ts diff --git a/src/plugins/discover/public/services/saved_searches/index.ts b/src/plugins/saved_search/public/services/saved_searches/index.ts similarity index 82% rename from src/plugins/discover/public/services/saved_searches/index.ts rename to src/plugins/saved_search/public/services/saved_searches/index.ts index c41c92df300846..fbdcfbf5793c6b 100644 --- a/src/plugins/discover/public/services/saved_searches/index.ts +++ b/src/plugins/saved_search/public/services/saved_searches/index.ts @@ -13,8 +13,6 @@ export { getSavedSearchUrlConflictMessage, throwErrorOnSavedSearchUrlConflict, } from './saved_searches_utils'; -export { useSavedSearchAliasMatchRedirect } from './saved_search_alias_match_redirect'; -export { SavedSearchURLConflictCallout } from './saved_search_url_conflict_callout'; export type { SaveSavedSearchOptions } from './save_saved_searches'; export { saveSavedSearch } from './save_saved_searches'; export { SAVED_SEARCH_TYPE } from './constants'; diff --git a/src/plugins/discover/public/services/saved_searches/save_saved_searches.test.ts b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/save_saved_searches.test.ts rename to src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts diff --git a/src/plugins/discover/public/services/saved_searches/save_saved_searches.ts b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/save_saved_searches.ts rename to src/plugins/saved_search/public/services/saved_searches/save_saved_searches.ts diff --git a/src/plugins/discover/public/services/saved_searches/saved_searches_utils.test.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts similarity index 100% rename from src/plugins/discover/public/services/saved_searches/saved_searches_utils.test.ts rename to src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts diff --git a/src/plugins/discover/public/services/saved_searches/saved_searches_utils.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts similarity index 92% rename from src/plugins/discover/public/services/saved_searches/saved_searches_utils.ts rename to src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts index 5c13c9d78cb9e3..cb20b242879430 100644 --- a/src/plugins/discover/public/services/saved_searches/saved_searches_utils.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts @@ -8,13 +8,10 @@ import { i18n } from '@kbn/i18n'; import type { SavedSearchAttributes, SavedSearch } from './types'; -export { - getSavedSearchUrl, - getSavedSearchFullPathUrl, -} from '../../../common/services/saved_searches'; +export { getSavedSearchUrl, getSavedSearchFullPathUrl } from '../../../common'; export const getSavedSearchUrlConflictMessage = async (savedSearch: SavedSearch) => - i18n.translate('discover.savedSearchEmbeddable.legacyURLConflict.errorMessage', { + i18n.translate('savedSearch.legacyURLConflict.errorMessage', { defaultMessage: `This search has the same URL as a legacy alias. Disable the alias to resolve this error : {json}`, values: { json: savedSearch.sharingSavedObjectProps?.errorJSON, diff --git a/src/plugins/discover/public/services/saved_searches/types.ts b/src/plugins/saved_search/public/services/saved_searches/types.ts similarity index 86% rename from src/plugins/discover/public/services/saved_searches/types.ts rename to src/plugins/saved_search/public/services/saved_searches/types.ts index fe47dedf6013da..e0c1e8be4a3ed7 100644 --- a/src/plugins/discover/public/services/saved_searches/types.ts +++ b/src/plugins/saved_search/public/services/saved_searches/types.ts @@ -8,8 +8,19 @@ import type { ResolvedSimpleSavedObject } from '@kbn/core/public'; import type { ISearchSource } from '@kbn/data-plugin/public'; -import { DiscoverGridSettingsColumn } from '../../components/discover_grid/types'; -import { VIEW_MODE } from '../../components/view_mode_toggle'; + +export enum VIEW_MODE { + DOCUMENT_LEVEL = 'documents', + AGGREGATED_LEVEL = 'aggregated', +} + +export interface DiscoverGridSettings { + columns?: Record; +} + +export interface DiscoverGridSettingsColumn { + width?: number; +} /** @internal **/ export interface SavedSearchAttributes { diff --git a/src/plugins/saved_search/server/index.ts b/src/plugins/saved_search/server/index.ts new file mode 100644 index 00000000000000..4ec3dc6fea4918 --- /dev/null +++ b/src/plugins/saved_search/server/index.ts @@ -0,0 +1,11 @@ +/* + * 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 { SavedSearchServerPlugin } from './plugin'; + +export const plugin = () => new SavedSearchServerPlugin(); diff --git a/src/plugins/saved_search/server/plugin.ts b/src/plugins/saved_search/server/plugin.ts new file mode 100644 index 00000000000000..ca41ed81e40880 --- /dev/null +++ b/src/plugins/saved_search/server/plugin.ts @@ -0,0 +1,33 @@ +/* + * 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 { CoreSetup, CoreStart, Plugin } from '@kbn/core/server'; +import type { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server'; +import { getSavedSearchObjectType } from './saved_objects'; + +export class SavedSearchServerPlugin implements Plugin { + public setup( + core: CoreSetup, + plugins: { + data: DataPluginSetup; + } + ) { + const getSearchSourceMigrations = plugins.data.search.searchSource.getAllMigrations.bind( + plugins.data.search.searchSource + ); + core.savedObjects.registerType(getSavedSearchObjectType(getSearchSourceMigrations)); + + return {}; + } + + public start(core: CoreStart) { + return {}; + } + + public stop() {} +} diff --git a/src/plugins/discover/server/saved_objects/index.ts b/src/plugins/saved_search/server/saved_objects/index.ts similarity index 100% rename from src/plugins/discover/server/saved_objects/index.ts rename to src/plugins/saved_search/server/saved_objects/index.ts diff --git a/src/plugins/discover/server/saved_objects/search.ts b/src/plugins/saved_search/server/saved_objects/search.ts similarity index 100% rename from src/plugins/discover/server/saved_objects/search.ts rename to src/plugins/saved_search/server/saved_objects/search.ts diff --git a/src/plugins/discover/server/saved_objects/search_migrations.test.ts b/src/plugins/saved_search/server/saved_objects/search_migrations.test.ts similarity index 100% rename from src/plugins/discover/server/saved_objects/search_migrations.test.ts rename to src/plugins/saved_search/server/saved_objects/search_migrations.test.ts diff --git a/src/plugins/discover/server/saved_objects/search_migrations.ts b/src/plugins/saved_search/server/saved_objects/search_migrations.ts similarity index 100% rename from src/plugins/discover/server/saved_objects/search_migrations.ts rename to src/plugins/saved_search/server/saved_objects/search_migrations.ts diff --git a/src/plugins/saved_search/tsconfig.json b/src/plugins/saved_search/tsconfig.json new file mode 100644 index 00000000000000..3bfddf5ff58589 --- /dev/null +++ b/src/plugins/saved_search/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "../../../typings/**/*", + ], + "references": [ + { "path": "../../core/tsconfig.json" }, + { "path": "../data/tsconfig.json" }, + { "path": "../kibana_utils/tsconfig.json" }, + { "path": "../../../x-pack/plugins/spaces/tsconfig.json" } + ] +} diff --git a/src/plugins/visualizations/kibana.json b/src/plugins/visualizations/kibana.json index 62627208561da1..69b9eb6c2b0902 100644 --- a/src/plugins/visualizations/kibana.json +++ b/src/plugins/visualizations/kibana.json @@ -19,7 +19,7 @@ "dataViewEditor" ], "optionalPlugins": ["home", "share", "spaces", "savedObjectsTaggingOss"], - "requiredBundles": ["kibanaUtils", "discover", "kibanaReact"], + "requiredBundles": ["kibanaUtils", "savedSearch", "kibanaReact"], "extraPublicDirs": ["common/constants", "common/utils", "common/expression_functions"], "owner": { "name": "Vis Editors", diff --git a/src/plugins/visualizations/public/vis.ts b/src/plugins/visualizations/public/vis.ts index 8e89fa86199472..003a894fdfe119 100644 --- a/src/plugins/visualizations/public/vis.ts +++ b/src/plugins/visualizations/public/vis.ts @@ -26,7 +26,7 @@ import { getSavedSearch, SavedSearch, throwErrorOnSavedSearchUrlConflict, -} from '@kbn/discover-plugin/public'; +} from '@kbn/saved-search-plugin/public'; import { PersistedState } from './persisted_state'; import { getTypes, diff --git a/src/plugins/visualizations/public/visualize_app/types.ts b/src/plugins/visualizations/public/visualize_app/types.ts index e7e213d3a6416f..88672430c25500 100644 --- a/src/plugins/visualizations/public/visualize_app/types.ts +++ b/src/plugins/visualizations/public/visualize_app/types.ts @@ -37,7 +37,7 @@ import type { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { SavedSearch } from '@kbn/discover-plugin/public'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import type { Vis, VisualizeEmbeddableContract, diff --git a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.test.ts b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.test.ts index ebc17b1e32c91e..7e7f3eee7624ae 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.test.ts +++ b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { getSavedSearch } from '@kbn/discover-plugin/public'; +import { getSavedSearch } from '@kbn/saved-search-plugin/public'; import type { VisualizeInput, VisSavedObject, Vis, VisParams } from '../..'; import { getVisualizationInstance, @@ -38,7 +38,7 @@ jest.mock('../../vis_async', () => ({ })); const { createVisAsync } = jest.requireMock('../../vis_async'); -jest.mock('@kbn/discover-plugin/public', () => ({ +jest.mock('@kbn/saved-search-plugin/public', () => ({ getSavedSearch: jest.fn().mockResolvedValue({ id: 'savedSearch', title: 'savedSearchTitle', diff --git a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts index 925f22d68a20e9..4049f8242a02a4 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts +++ b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts @@ -13,7 +13,7 @@ import { getSavedSearch, SavedSearch, throwErrorOnSavedSearchUrlConflict, -} from '@kbn/discover-plugin/public'; +} from '@kbn/saved-search-plugin/public'; import { createVisAsync } from '../../vis_async'; import { convertToSerializedVis, getSavedVisualization } from '../../utils/saved_visualize_utils'; import { diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index e44374e23f623a..02eda42929b9fa 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -24,7 +24,7 @@ { "path": "../saved_objects_tagging_oss/tsconfig.json" }, { "path": "../kibana_utils/tsconfig.json" }, { "path": "../kibana_react/tsconfig.json" }, - { "path": "../discover/tsconfig.json" }, + { "path": "../saved_search/tsconfig.json" }, { "path": "../url_forwarding/tsconfig.json" }, { "path": "../navigation/tsconfig.json" }, { "path": "../home/tsconfig.json" }, diff --git a/tsconfig.base.json b/tsconfig.base.json index 04afc7e8bb049d..36988b9e4e9f01 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -145,6 +145,8 @@ "@kbn/saved-objects-tagging-oss-plugin/*": ["src/plugins/saved_objects_tagging_oss/*"], "@kbn/saved-objects-plugin": ["src/plugins/saved_objects"], "@kbn/saved-objects-plugin/*": ["src/plugins/saved_objects/*"], + "@kbn/saved-search-plugin": ["src/plugins/saved_search"], + "@kbn/saved-search-plugin/*": ["src/plugins/saved_search/*"], "@kbn/screenshot-mode-plugin": ["src/plugins/screenshot_mode"], "@kbn/screenshot-mode-plugin/*": ["src/plugins/screenshot_mode/*"], "@kbn/share-plugin": ["src/plugins/share"], diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 82ada1663827e6..1bfeeed7b67576 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -3189,7 +3189,6 @@ "discover.savedSearch.savedObjectName": "Recherche enregistrée", "discover.savedSearchAliasMatchRedirect.objectNoun": "Recherche {savedSearch}", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "Ouvrir dans Discover", - "discover.savedSearchEmbeddable.legacyURLConflict.errorMessage": "Cette recherche a la même URL qu'un alias hérité. Désactiver l'alias pour résoudre cette erreur : {json}", "discover.savedSearchURLConflictCallout.objectNoun": "Recherche {savedSearch}", "discover.searchGenerationWithDescription": "Tableau généré par la recherche {searchTitle}", "discover.searchGenerationWithDescriptionGrid": "Tableau généré par la recherche {searchTitle} ({searchDescription})", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f0b52ae8beea70..e2ffbe8d109e9d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3187,7 +3187,6 @@ "discover.savedSearch.savedObjectName": "保存検索", "discover.savedSearchAliasMatchRedirect.objectNoun": "{savedSearch}検索", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "Discoverで開く", - "discover.savedSearchEmbeddable.legacyURLConflict.errorMessage": "この検索にはレガシーエイリアスと同じURLがあります。このエラーを解決するには、エイリアスを無効にしてください:{json}", "discover.savedSearchURLConflictCallout.objectNoun": "{savedSearch}検索", "discover.searchGenerationWithDescription": "検索{searchTitle}で生成されたテーブル", "discover.searchGenerationWithDescriptionGrid": "検索{searchTitle}で生成されたテーブル({searchDescription})", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f90be8e7f1debe..1da6b2b3350f02 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3190,7 +3190,6 @@ "discover.savedSearch.savedObjectName": "已保存搜索", "discover.savedSearchAliasMatchRedirect.objectNoun": "{savedSearch} 搜索", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "在 Discover 中打开", - "discover.savedSearchEmbeddable.legacyURLConflict.errorMessage": "此搜索具有与旧版别名相同的 URL。请禁用别名以解决此错误:{json}", "discover.savedSearchURLConflictCallout.objectNoun": "{savedSearch} 搜索", "discover.searchGenerationWithDescription": "搜索 {searchTitle} 生成的表", "discover.searchGenerationWithDescriptionGrid": "搜索 {searchTitle} 生成的表({searchDescription})", From 79763f258181187740e64a8f682a8270481b8be3 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 12 Aug 2022 12:41:28 +0300 Subject: [PATCH 42/59] [Lens] Fix Introduce error boundary for visualizations (#137710) * [Lens] Fix Introduce error boundary for visualizations Closes: #132582 * fix error handling for embeddable * update error_helper.ts * add checks for some methods * add memoizedErrorNotification * add more try/catch'es Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Joe Reuter --- .../public/app_plugin/show_underlying_data.ts | 26 +++-- x-pack/plugins/lens/public/async_services.ts | 1 + .../editor_frame/editor_frame.tsx | 76 +++++++++------ .../editor_frame/state_helpers.ts | 34 +++++-- .../editor_frame/suggestion_helpers.ts | 96 +++++++++++-------- .../editor_frame/suggestion_panel.tsx | 68 +++++++------ .../workspace_panel/chart_switch.tsx | 39 ++++++-- .../editor_frame_service/error_helper.ts | 2 + .../lens/public/embeddable/embeddable.tsx | 5 +- .../public/embeddable/embeddable_factory.ts | 90 +++++++++-------- .../public/lens_ui_errors/error_boundary.tsx | 52 ++++++++++ .../lens/public/lens_ui_errors/index.ts | 12 +++ .../memoized_error_notification.tsx | 40 ++++++++ x-pack/plugins/lens/public/plugin.ts | 15 ++- 14 files changed, 384 insertions(+), 172 deletions(-) create mode 100644 x-pack/plugins/lens/public/lens_ui_errors/error_boundary.tsx create mode 100644 x-pack/plugins/lens/public/lens_ui_errors/index.ts create mode 100644 x-pack/plugins/lens/public/lens_ui_errors/memoized_error_notification.tsx diff --git a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts index 310e91d3caaad6..e678ad5ddf00db 100644 --- a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts +++ b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts @@ -19,8 +19,9 @@ import { i18n } from '@kbn/i18n'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Capabilities } from '@kbn/core/public'; import { partition } from 'lodash'; +import { showMemoizedErrorNotification } from '../lens_ui_errors'; import { TableInspectorAdapter } from '../editor_frame_service/types'; -import { Datasource } from '../types'; +import { Datasource, DatasourcePublicAPI } from '../types'; /** * Joins a series of queries. @@ -89,11 +90,24 @@ export function getLayerMetaInfo( isVisible, }; } - const [firstLayerId] = currentDatasource.getLayers(datasourceState); - const datasourceAPI = currentDatasource.getPublicAPI({ - layerId: firstLayerId, - state: datasourceState, - }); + + let datasourceAPI: DatasourcePublicAPI; + + try { + const [firstLayerId] = currentDatasource.getLayers(datasourceState); + datasourceAPI = currentDatasource.getPublicAPI({ + layerId: firstLayerId, + state: datasourceState, + }); + } catch (error) { + showMemoizedErrorNotification(error); + + return { + meta: undefined, + error: error.message, + isVisible, + }; + } // maybe add also datasourceId validation here? if (datasourceAPI.datasourceId !== 'indexpattern') { return { diff --git a/x-pack/plugins/lens/public/async_services.ts b/x-pack/plugins/lens/public/async_services.ts index 9025b738c2e1f3..1740354de78806 100644 --- a/x-pack/plugins/lens/public/async_services.ts +++ b/x-pack/plugins/lens/public/async_services.ts @@ -34,6 +34,7 @@ export { createFormulaPublicApi } from './indexpattern_datasource/operations/def export * from './indexpattern_datasource'; export * from './lens_ui_telemetry'; +export * from './lens_ui_errors'; export * from './editor_frame_service/editor_frame'; export * from './editor_frame_service'; export * from './embeddable'; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx index 0b1847204bd1d5..5f4845e46ce3f7 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx @@ -28,6 +28,7 @@ import { selectVisualization, } from '../../state_management'; import type { LensInspector } from '../../lens_inspector_service'; +import { ErrorBoundary, showMemoizedErrorNotification } from '../../lens_ui_errors'; export interface EditorFrameProps { datasourceMap: DatasourceMap; @@ -50,6 +51,7 @@ export function EditorFrame(props: EditorFrameProps) { const visualizationTypeIsKnown = Boolean( visualization.activeId && props.visualizationMap[visualization.activeId] ); + const framePublicAPI: FramePublicAPI = useLensSelector((state) => selectFramePublicAPI(state, datasourceMap) ); @@ -85,54 +87,66 @@ export function EditorFrame(props: EditorFrameProps) { [getSuggestionForField, dispatchLens] ); + const onError = useCallback((error: Error) => { + showMemoizedErrorNotification(error); + }, []); + return ( - } - configPanel={ - areDatasourcesLoaded && ( - + + + } + configPanel={ + areDatasourcesLoaded && ( + + + ) } workspacePanel={ areDatasourcesLoaded && isVisualizationLoaded && ( - + + + ) } suggestionsPanel={ visualizationTypeIsKnown && areDatasourcesLoaded && ( - + + + ) } /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts index 1790a18ad12486..b4f00f273cd2d7 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts @@ -20,6 +20,7 @@ import { VisualizeEditorContext, } from '../../types'; import { buildExpression } from './expression_helpers'; +import { showMemoizedErrorNotification } from '../../lens_ui_errors'; import { Document } from '../../persistence/saved_object_store'; import { getActiveDatasourceIdFromDoc } from '../../utils'; import { ErrorMessage } from '../types'; @@ -196,16 +197,29 @@ export const validateDatasourceAndVisualization = ( currentVisualizationState: unknown | undefined, frameAPI: Pick ): ErrorMessage[] | undefined => { - const datasourceValidationErrors = currentDatasourceState - ? currentDataSource?.getErrorMessages(currentDatasourceState) - : undefined; - - const visualizationValidationErrors = currentVisualizationState - ? currentVisualization?.getErrorMessages(currentVisualizationState, frameAPI.datasourceLayers) - : undefined; - - if (datasourceValidationErrors?.length || visualizationValidationErrors?.length) { - return [...(datasourceValidationErrors || []), ...(visualizationValidationErrors || [])]; + try { + const datasourceValidationErrors = currentDatasourceState + ? currentDataSource?.getErrorMessages(currentDatasourceState) + : undefined; + + const visualizationValidationErrors = currentVisualizationState + ? currentVisualization?.getErrorMessages(currentVisualizationState, frameAPI.datasourceLayers) + : undefined; + + if (datasourceValidationErrors?.length || visualizationValidationErrors?.length) { + return [...(datasourceValidationErrors || []), ...(visualizationValidationErrors || [])]; + } + } catch (e) { + showMemoizedErrorNotification(e); + if (e.message) { + return [ + { + shortMessage: e.message, + longMessage: e.message, + type: 'critical', + }, + ]; + } } return undefined; }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index edbf843838a48c..620de25aa52946 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -8,6 +8,7 @@ import { Datatable } from '@kbn/expressions-plugin/common'; import type { PaletteOutput } from '@kbn/coloring'; import { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; +import { showMemoizedErrorNotification } from '../../lens_ui_errors'; import { Visualization, Datasource, @@ -85,34 +86,40 @@ export function getSuggestions({ const datasourceTableSuggestions = datasources.flatMap(([datasourceId, datasource]) => { const datasourceState = datasourceStates[datasourceId].state; let dataSourceSuggestions; - // context is used to pass the state from location to datasource - if (visualizeTriggerFieldContext) { - // used for navigating from VizEditor to Lens - if ('isVisualizeAction' in visualizeTriggerFieldContext) { - dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeCharts( + + try { + // context is used to pass the state from location to datasource + if (visualizeTriggerFieldContext) { + // used for navigating from VizEditor to Lens + if ('isVisualizeAction' in visualizeTriggerFieldContext) { + dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeCharts( + datasourceState, + visualizeTriggerFieldContext.layers + ); + } else { + // used for navigating from Discover to Lens + dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeField( + datasourceState, + visualizeTriggerFieldContext.indexPatternId, + visualizeTriggerFieldContext.fieldName + ); + } + } else if (field) { + dataSourceSuggestions = datasource.getDatasourceSuggestionsForField( datasourceState, - visualizeTriggerFieldContext.layers + field, + (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]) // a field dragged to workspace should added to data layer ); } else { - // used for navigating from Discover to Lens - dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeField( + dataSourceSuggestions = datasource.getDatasourceSuggestionsFromCurrentState( datasourceState, - visualizeTriggerFieldContext.indexPatternId, - visualizeTriggerFieldContext.fieldName + (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]), + activeData ); } - } else if (field) { - dataSourceSuggestions = datasource.getDatasourceSuggestionsForField( - datasourceState, - field, - (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]) // a field dragged to workspace should added to data layer - ); - } else { - dataSourceSuggestions = datasource.getDatasourceSuggestionsFromCurrentState( - datasourceState, - (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]), - activeData - ); + } catch (error) { + showMemoizedErrorNotification(error); + return []; } return dataSourceSuggestions.map((suggestion) => ({ ...suggestion, datasourceId })); }); @@ -211,26 +218,31 @@ function getVisualizationSuggestions( isFromContext?: boolean, activeData?: Record ) { - return visualization - .getSuggestions({ - table, - state: currentVisualizationState, - keptLayerIds: datasourceSuggestion.keptLayerIds, - subVisualizationId, - mainPalette, - isFromContext, - activeData, - }) - .map(({ state, ...visualizationSuggestion }) => ({ - ...visualizationSuggestion, - visualizationId, - visualizationState: state, - keptLayerIds: datasourceSuggestion.keptLayerIds, - datasourceState: datasourceSuggestion.state, - datasourceId: datasourceSuggestion.datasourceId, - columns: table.columns.length, - changeType: table.changeType, - })); + try { + return visualization + .getSuggestions({ + table, + state: currentVisualizationState, + keptLayerIds: datasourceSuggestion.keptLayerIds, + subVisualizationId, + mainPalette, + isFromContext, + activeData, + }) + .map(({ state, ...visualizationSuggestion }) => ({ + ...visualizationSuggestion, + visualizationId, + visualizationState: state, + keptLayerIds: datasourceSuggestion.keptLayerIds, + datasourceState: datasourceSuggestion.state, + datasourceId: datasourceSuggestion.datasourceId, + columns: table.columns.length, + changeType: table.changeType, + })); + } catch (e) { + showMemoizedErrorNotification(e); + return []; + } } export function switchToSuggestion( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 67403b93d7b8cd..9eafb0476afd3d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -40,6 +40,7 @@ import { } from '../../types'; import { getSuggestions, switchToSuggestion } from './suggestion_helpers'; import { getDatasourceExpressionsByLayers } from './expression_helpers'; +import { showMemoizedErrorNotification } from '../../lens_ui_errors/memoized_error_notification'; import { getMissingIndexPattern, validateDatasourceAndVisualization, @@ -493,39 +494,44 @@ function getPreviewExpression( datasourceLayers: { ...frame.datasourceLayers }, }; - // use current frame api and patch apis for changed datasource layers - if ( - visualizableState.keptLayerIds && - visualizableState.datasourceId && - visualizableState.datasourceState - ) { - const datasource = datasources[visualizableState.datasourceId]; - const datasourceState = visualizableState.datasourceState; - const updatedLayerApis: DatasourceLayers = pick( - frame.datasourceLayers, - visualizableState.keptLayerIds - ); - const changedLayers = datasource.getLayers(visualizableState.datasourceState); - changedLayers.forEach((layerId) => { - if (updatedLayerApis[layerId]) { - updatedLayerApis[layerId] = datasource.getPublicAPI({ - layerId, - state: datasourceState, - }); - } - }); - } + try { + // use current frame api and patch apis for changed datasource layers + if ( + visualizableState.keptLayerIds && + visualizableState.datasourceId && + visualizableState.datasourceState + ) { + const datasource = datasources[visualizableState.datasourceId]; + const datasourceState = visualizableState.datasourceState; + const updatedLayerApis: DatasourceLayers = pick( + frame.datasourceLayers, + visualizableState.keptLayerIds + ); + const changedLayers = datasource.getLayers(visualizableState.datasourceState); + changedLayers.forEach((layerId) => { + if (updatedLayerApis[layerId]) { + updatedLayerApis[layerId] = datasource.getPublicAPI({ + layerId, + state: datasourceState, + }); + } + }); + } - const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( - datasources, - datasourceStates - ); + const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( + datasources, + datasourceStates + ); - return visualization.toPreviewExpression( - visualizableState.visualizationState, - suggestionFrameApi.datasourceLayers, - datasourceExpressionsByLayers ?? undefined - ); + return visualization.toPreviewExpression( + visualizableState.visualizationState, + suggestionFrameApi.datasourceLayers, + datasourceExpressionsByLayers ?? undefined + ); + } catch (error) { + showMemoizedErrorNotification(error); + return null; + } } function preparePreviewExpression( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx index 8f9e7e53af78d3..7e1e489298250b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx @@ -30,6 +30,7 @@ import { Suggestion, } from '../../../types'; import { getSuggestions, switchToSuggestion } from '../suggestion_helpers'; +import { showMemoizedErrorNotification } from '../../../lens_ui_errors'; import { insertLayer, removeLayers, @@ -106,11 +107,23 @@ function computeListHeight(list: SelectableEntry[], maxHeight: number): number { return Math.min(list.length * ENTRY_HEIGHT, maxHeight); } +function safeFnCall(action: () => TReturn, defaultReturnValue: TReturn): TReturn { + try { + return action(); + } catch (error) { + showMemoizedErrorNotification(error); + return defaultReturnValue; + } +} + function getCurrentVisualizationId( activeVisualization: Visualization, visualizationState: unknown ) { - return activeVisualization.getVisualizationTypeId(visualizationState); + return safeFnCall( + () => activeVisualization.getVisualizationTypeId(visualizationState), + undefined + ); } export const ChartSwitch = memo(function ChartSwitch(props: Props) { @@ -150,9 +163,15 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) { subVisualizationId: string ): VisualizationSelection { const newVisualization = props.visualizationMap[visualizationId]; - const switchVisType = - props.visualizationMap[visualizationId].switchVisualizationType || - ((_type: string, initialState: unknown) => initialState); + const switchVisType = (type: string, state: unknown) => { + if (props.visualizationMap[visualizationId].switchVisualizationType) { + return safeFnCall( + () => props.visualizationMap[visualizationId].switchVisualizationType!(type, state), + state + ); + } + return state; + }; const layers = Object.entries(props.framePublicAPI.datasourceLayers); const containsData = layers.some( ([_layerId, datasource]) => datasource && datasource.getTableSpec().length > 0 @@ -161,7 +180,10 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) { if ( visualization.activeId === visualizationId && visualization.state && - newVisualization.getVisualizationTypeId(visualization.state) === subVisualizationId + safeFnCall( + () => newVisualization.getVisualizationTypeId(visualization.state) === subVisualizationId, + false + ) ) { return { visualizationId, @@ -502,7 +524,12 @@ function getTopSuggestion( // to avoid confusing the user. return ( suggestion.changeType !== 'extended' && - newVisualization.getVisualizationTypeId(suggestion.visualizationState) === subVisualizationId + safeFnCall( + () => + newVisualization.getVisualizationTypeId(suggestion.visualizationState) === + subVisualizationId, + false + ) ); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts b/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts index f9a2c2efcdc226..17ca0172b6df43 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/error_helper.ts @@ -143,6 +143,8 @@ export function getOriginalRequestErrorMessages(error?: ExpressionRenderError | } } } + } else if (error?.message) { + errorMessages.push(error?.message); } return errorMessages; } diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 115cd4691ad67d..7376c9328afe8f 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -273,7 +273,10 @@ export class Embeddable this.lensInspector = getLensInspectorService(deps.inspector); this.expressionRenderer = deps.expressionRenderer; - this.initializeSavedVis(initialInput).then(() => this.onContainerStateChanged(initialInput)); + this.initializeSavedVis(initialInput) + .then(() => this.onContainerStateChanged(initialInput)) + .catch((e) => this.onFatalError(e)); + this.subscription = this.getUpdated$().subscribe(() => this.onContainerStateChanged(this.input) ); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts index 07c5a5bdf5ef7d..559ba9d780ff0f 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts @@ -18,7 +18,11 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { DataPublicPluginStart, FilterManager, TimefilterContract } from '@kbn/data-plugin/public'; import type { DataViewsContract } from '@kbn/data-views-plugin/public'; import { ReactExpressionRendererType } from '@kbn/expressions-plugin/public'; -import { EmbeddableFactoryDefinition, IContainer } from '@kbn/embeddable-plugin/public'; +import { + EmbeddableFactoryDefinition, + IContainer, + ErrorEmbeddable, +} from '@kbn/embeddable-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { Start as InspectorStart } from '@kbn/inspector-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; @@ -91,57 +95,61 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { }; async create(input: LensEmbeddableInput, parent?: IContainer) { - const { - data, - timefilter, - expressionRenderer, - documentToExpression, - injectFilterReferences, - visualizationMap, - datasourceMap, - uiActions, - coreHttp, - attributeService, - indexPatternService, - capabilities, - usageCollection, - theme, - inspector, - spaces, - uiSettings, - } = await this.getStartServices(); - - const { Embeddable } = await import('../async_services'); - - return new Embeddable( - { - attributeService, + try { + const { data, - indexPatternService, timefilter, - inspector, expressionRenderer, - basePath: coreHttp.basePath, - getTrigger: uiActions?.getTrigger, - getTriggerCompatibleActions: uiActions?.getTriggerCompatibleActions, documentToExpression, injectFilterReferences, visualizationMap, datasourceMap, - capabilities: { - canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls), - canSaveVisualizations: Boolean(capabilities.visualize.save), - navLinks: capabilities.navLinks, - discover: capabilities.discover, - }, + uiActions, + coreHttp, + attributeService, + indexPatternService, + capabilities, usageCollection, theme, + inspector, spaces, uiSettings, - }, - input, - parent - ); + } = await this.getStartServices(); + + const { Embeddable } = await import('../async_services'); + + return new Embeddable( + { + attributeService, + data, + indexPatternService, + timefilter, + inspector, + expressionRenderer, + basePath: coreHttp.basePath, + getTrigger: uiActions?.getTrigger, + getTriggerCompatibleActions: uiActions?.getTriggerCompatibleActions, + documentToExpression, + injectFilterReferences, + visualizationMap, + datasourceMap, + capabilities: { + canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls), + canSaveVisualizations: Boolean(capabilities.visualize.save), + navLinks: capabilities.navLinks, + discover: capabilities.discover, + }, + usageCollection, + theme, + spaces, + uiSettings, + }, + input, + parent + ); + } catch (e) { + return new ErrorEmbeddable(e, input, parent); + } } extract = extract; diff --git a/x-pack/plugins/lens/public/lens_ui_errors/error_boundary.tsx b/x-pack/plugins/lens/public/lens_ui_errors/error_boundary.tsx new file mode 100644 index 00000000000000..ff62171d42df7a --- /dev/null +++ b/x-pack/plugins/lens/public/lens_ui_errors/error_boundary.tsx @@ -0,0 +1,52 @@ +/* + * 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 { EuiErrorBoundary } from '@elastic/eui'; + +interface ErrorBoundaryProps { + children: JSX.Element; + onError?: (error: Error) => void; +} + +interface ErrorBoundaryState { + originalError?: Error; +} + +/** @internal **/ +const RecallError = ({ error }: { error: Error }) => { + throw error; +}; + +export class ErrorBoundary extends React.Component { + constructor(props: ErrorBoundaryProps) { + super(props); + } + + static getDerivedStateFromError(error: Error) { + // Update state so the next render will show the fallback UI. + return { originalError: error }; + } + + componentDidCatch(error: Error) { + this.props.onError?.(error); + } + + componentWillReceiveProps() { + this.setState({ originalError: undefined }); + } + + render() { + return this.state?.originalError ? ( + + + + ) : ( + this.props.children + ); + } +} diff --git a/x-pack/plugins/lens/public/lens_ui_errors/index.ts b/x-pack/plugins/lens/public/lens_ui_errors/index.ts new file mode 100644 index 00000000000000..f4906d7667d6a1 --- /dev/null +++ b/x-pack/plugins/lens/public/lens_ui_errors/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export { ErrorBoundary } from './error_boundary'; +export { + initMemoizedErrorNotification, + showMemoizedErrorNotification, +} from './memoized_error_notification'; diff --git a/x-pack/plugins/lens/public/lens_ui_errors/memoized_error_notification.tsx b/x-pack/plugins/lens/public/lens_ui_errors/memoized_error_notification.tsx new file mode 100644 index 00000000000000..75ea4d9d73ecab --- /dev/null +++ b/x-pack/plugins/lens/public/lens_ui_errors/memoized_error_notification.tsx @@ -0,0 +1,40 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import type { CoreStart } from '@kbn/core/public'; +import { createGetterSetter } from '@kbn/kibana-utils-plugin/common'; + +const [getMemoizedErrorNotification, setMemoizedErrorNotification] = createGetterSetter< + ReturnType +>('MemoizedErrorNotification', false); + +const memoizedErrorNotificationFactory = (coreStart: CoreStart) => { + const showedErrors = new Map(); + return (error: Error) => { + const { message } = error; + + if (message) { + if (!showedErrors.has(message)) { + coreStart.notifications.toasts.addError(error, { + title: i18n.translate('xpack.lens.uiErrors.unexpectedError', { + defaultMessage: 'An unexpected error occurred.', + }), + }); + showedErrors.set(message, true); + } + } + }; +}; + +const showMemoizedErrorNotification = (error: Error) => getMemoizedErrorNotification()?.(error); + +const initMemoizedErrorNotification = (coreStart: CoreStart) => { + setMemoizedErrorNotification(memoizedErrorNotificationFactory(coreStart)); +}; + +export { showMemoizedErrorNotification, initMemoizedErrorNotification }; diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 99585a0fd9a77b..345a27a1e01a00 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -253,7 +253,8 @@ export class LensPlugin { const startServices = createStartServicesGetter(core.getStartServices); const getStartServices = async (): Promise => { - const { getLensAttributeService, setUsageCollectionStart } = await import('./async_services'); + const { getLensAttributeService, setUsageCollectionStart, initMemoizedErrorNotification } = + await import('./async_services'); const { core: coreStart, plugins } = startServices(); await this.initParts( @@ -272,6 +273,8 @@ export class LensPlugin { setUsageCollectionStart(plugins.usageCollection); } + initMemoizedErrorNotification(coreStart); + return { attributeService: getLensAttributeService(coreStart, plugins), capabilities: coreStart.application.capabilities, @@ -339,13 +342,17 @@ export class LensPlugin { eventAnnotation ); - const { mountApp, getLensAttributeService, setUsageCollectionStart } = await import( - './async_services' - ); + const { + mountApp, + getLensAttributeService, + setUsageCollectionStart, + initMemoizedErrorNotification, + } = await import('./async_services'); if (deps.usageCollection) { setUsageCollectionStart(deps.usageCollection); } + initMemoizedErrorNotification(coreStart); const frameStart = this.editorFrameService!.start(coreStart, deps); return mountApp(core, params, { From a0b0a8b8e515b79376b83f1118e7acbb0a4c90a5 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 12 Aug 2022 05:43:06 -0400 Subject: [PATCH 43/59] Change debug message when security is disabled (#138667) --- .../security/server/authentication/authentication_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index dae112663b1978..50797c821e884d 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -121,7 +121,7 @@ export class AuthenticationService { // If security is disabled, then continue with no user credentials. if (!license.isEnabled()) { this.logger.debug( - 'Current license does not support any security features, authentication is not needed.' + 'Authentication is not required, as security features are disabled in Elasticsearch.' ); return t.authenticated(); } From aba8af4fedf8fa8f0b1c78f9de1ccc94b6fc64b7 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Fri, 12 Aug 2022 11:09:57 +0100 Subject: [PATCH 44/59] [Lens] Disabled actions can be rendered in Lens Embeddables (#138281) * reder disabled actions * add unit test for disabled action * update unit tests * Update src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx Co-authored-by: Jean-Louis Leysens * Update src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts Co-authored-by: Jean-Louis Leysens * Update src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts Co-authored-by: Jean-Louis Leysens * update snapshot Co-authored-by: Jean-Louis Leysens --- .../ui_actions/public/actions/action.ts | 12 ++++ .../build_eui_context_menu_panels.test.ts | 68 ++++++++++++++++++- .../build_eui_context_menu_panels.tsx | 1 + 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/plugins/ui_actions/public/actions/action.ts b/src/plugins/ui_actions/public/actions/action.ts index 99dfd1844c66d8..fd32a2ecdca239 100644 --- a/src/plugins/ui_actions/public/actions/action.ts +++ b/src/plugins/ui_actions/public/actions/action.ts @@ -98,6 +98,12 @@ export interface Action * false by default. */ shouldAutoExecute?(context: ActionExecutionContext): Promise; + + /** + * action is disabled or not + * + */ + disabled?: boolean; } /** @@ -139,6 +145,12 @@ export interface ActionDefinition * right-clicks and selects "Open in new tab". */ getHref?(context: ActionDefinitionContext): Promise; + + /** + * action is disabled or not + * + */ + disabled?: boolean; } export type ActionContext
    = A extends ActionDefinition ? Context : never; diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts index a117c98af49a93..5d37c3f1cdbe0a 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.test.ts @@ -16,11 +16,13 @@ const createTestAction = ({ dispayName, order, grouping = undefined, + disabled, }: { type?: string; dispayName: string; order?: number; grouping?: PresentableGrouping; + disabled?: boolean; }) => createAction({ id: type as string, @@ -29,11 +31,14 @@ const createTestAction = ({ order, execute: async () => {}, grouping, + disabled, }); const resultMapper = (panel: EuiContextMenuPanelDescriptor) => ({ items: panel.items - ? panel.items.map((item) => ({ name: item.isSeparator ? 'SEPARATOR' : item.name })) + ? panel.items.map((item) => + item.isSeparator ? { name: 'SEPARATOR' } : { name: item.name, disabled: item.disabled } + ) : [], }); @@ -75,15 +80,19 @@ test('sorts items in DESC order by "order" field first, then by display name', a Object { "items": Array [ Object { + "disabled": undefined, "name": "a-3", }, Object { + "disabled": undefined, "name": "a-2", }, Object { + "disabled": undefined, "name": "b-2", }, Object { + "disabled": undefined, "name": "More", }, ], @@ -91,9 +100,11 @@ test('sorts items in DESC order by "order" field first, then by display name', a Object { "items": Array [ Object { + "disabled": undefined, "name": "c-2", }, Object { + "disabled": undefined, "name": "a-1", }, ], @@ -138,6 +149,7 @@ test('can build menu with one action', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo", }, ], @@ -209,15 +221,19 @@ test('hides items behind in "More" submenu if there are more than 4 actions', as Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 1", }, Object { + "disabled": undefined, "name": "Foo 2", }, Object { + "disabled": undefined, "name": "Foo 3", }, Object { + "disabled": undefined, "name": "More", }, ], @@ -225,9 +241,11 @@ test('hides items behind in "More" submenu if there are more than 4 actions', as Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 4", }, Object { + "disabled": undefined, "name": "Foo 5", }, ], @@ -266,18 +284,22 @@ test('separates grouped items from main items with a separator', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 1", }, Object { + "disabled": undefined, "name": "Foo 2", }, Object { + "disabled": undefined, "name": "Foo 3", }, Object { "name": "SEPARATOR", }, Object { + "disabled": undefined, "name": "Foo 4", }, ], @@ -285,6 +307,7 @@ test('separates grouped items from main items with a separator', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 4", }, ], @@ -332,24 +355,29 @@ test('separates multiple groups each with its own separator', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 1", }, Object { + "disabled": undefined, "name": "Foo 2", }, Object { + "disabled": undefined, "name": "Foo 3", }, Object { "name": "SEPARATOR", }, Object { + "disabled": undefined, "name": "Foo 4", }, Object { "name": "SEPARATOR", }, Object { + "disabled": undefined, "name": "Foo 5", }, ], @@ -357,6 +385,7 @@ test('separates multiple groups each with its own separator', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 4", }, ], @@ -364,6 +393,7 @@ test('separates multiple groups each with its own separator', async () => { Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 5", }, ], @@ -402,12 +432,14 @@ test('does not add separator for first grouping if there are no main items', asy Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 4", }, Object { "name": "SEPARATOR", }, Object { + "disabled": undefined, "name": "Foo 5", }, ], @@ -415,6 +447,7 @@ test('does not add separator for first grouping if there are no main items', asy Object { "items": Array [ Object { + "disabled": undefined, "name": "Foo 4", }, ], @@ -422,6 +455,39 @@ test('does not add separator for first grouping if there are no main items', asy Object { "items": Array [ Object { + "disabled": undefined, + "name": "Foo 5", + }, + ], + }, + ] + `); +}); + +test('it creates disabled actions', async () => { + const actions = [ + createTestAction({ + dispayName: 'Foo 4', + disabled: true, + }), + createTestAction({ + dispayName: 'Foo 5', + }), + ]; + const menu = await buildContextMenuForActions({ + actions: actions.map((action) => ({ action, context: {}, trigger: { id: 'TEST' } })), + }); + + expect(menu.map(resultMapper)).toMatchInlineSnapshot(` + Array [ + Object { + "items": Array [ + Object { + "disabled": true, + "name": "Foo 4", + }, + Object { + "disabled": undefined, "name": "Foo 5", }, ], diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index d913ecdbf0b8fe..4904c38b0f825f 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -173,6 +173,7 @@ export async function buildContextMenuForActions({ href: action.getHref ? await action.getHref(context) : undefined, _order: action.order || 0, _title: action.getDisplayName(context), + disabled: action.disabled, }); }); await Promise.all(promises); From b9070807108716d8e1bfa140c65685b1a0f6ed56 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 12 Aug 2022 12:21:52 +0100 Subject: [PATCH 45/59] skip flaky suite (#60132) --- x-pack/test/functional/apps/security/security.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/security/security.ts b/x-pack/test/functional/apps/security/security.ts index 11e1525eb4bfd1..75748be05695d1 100644 --- a/x-pack/test/functional/apps/security/security.ts +++ b/x-pack/test/functional/apps/security/security.ts @@ -16,7 +16,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const spaces = getService('spaces'); - describe('Security', function () { + // FLAKY: https://github.com/elastic/kibana/issues/60132 + describe.skip('Security', function () { this.tags('includeFirefox'); describe('Login Page', () => { before(async () => { From 339f9068fc068ee0f7312206ace5acd7426a3478 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Fri, 12 Aug 2022 07:38:22 -0400 Subject: [PATCH 46/59] [build] Update copyAll implementation (#138692) * [build] Update copyAll implementation * remove unused copy --- src/dev/build/lib/fs.ts | 41 ++++++++----------- .../tasks/os_packages/docker_generator/run.ts | 7 ---- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/dev/build/lib/fs.ts b/src/dev/build/lib/fs.ts index e34495409a8f9b..3bf035e0fc04a3 100644 --- a/src/dev/build/lib/fs.ts +++ b/src/dev/build/lib/fs.ts @@ -9,15 +9,14 @@ import fs from 'fs'; import Fsp from 'fs/promises'; import { createHash } from 'crypto'; -import { Writable } from 'stream'; import { pipeline } from 'stream/promises'; import { resolve, dirname, isAbsolute, sep } from 'path'; import { createGunzip } from 'zlib'; import { inspect } from 'util'; import archiver from 'archiver'; -import vfs from 'vinyl-fs'; -import File from 'vinyl'; +import globby from 'globby'; +import cpy from 'cpy'; import del from 'del'; import deleteEmpty from 'delete-empty'; import tar, { ExtractOptions } from 'tar'; @@ -155,32 +154,24 @@ export async function copyAll( assertAbsolute(sourceDir); assertAbsolute(destination); - await pipeline( - vfs.src(select, { - buffer: false, - cwd: sourceDir, - base: sourceDir, - dot, - }), - vfs.dest(destination) - ); + const copiedFiles = await cpy(select, destination, { + cwd: sourceDir, + parents: true, + ignoreJunk: false, + dot, + }); // we must update access and modified file times after the file copy // has completed, otherwise the copy action can effect modify times. if (time) { - await pipeline( - vfs.src(select, { - buffer: false, - cwd: destination, - base: destination, - dot, - }), - new Writable({ - objectMode: true, - write(file: File, _, cb) { - Fsp.utimes(file.path, time, time).then(() => cb(), cb); - }, - }) + const copiedDirectories = await globby(select, { + cwd: destination, + dot, + onlyDirectories: true, + absolute: true, + }); + await Promise.all( + [...copiedFiles, ...copiedDirectories].map((entry) => Fsp.utimes(entry, time, time)) ); } } diff --git a/src/dev/build/tasks/os_packages/docker_generator/run.ts b/src/dev/build/tasks/os_packages/docker_generator/run.ts index 34b58e7513bb16..89944999392efe 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/run.ts +++ b/src/dev/build/tasks/os_packages/docker_generator/run.ts @@ -131,13 +131,6 @@ export async function runDockerGenerator( dockerBuildDir ); - if (flags.ironbank) { - await copyAll( - config.resolveFromRepo('src/dev/build/tasks/os_packages/docker_generator/resources/ironbank'), - dockerBuildDir - ); - } - // Build docker image into the target folder // In order to do this we just call the file we // created from the templates/build_docker_sh.template.js From 137994f845dedae7caf0cbff756eba48b536b0d5 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Fri, 12 Aug 2022 14:00:41 +0200 Subject: [PATCH 47/59] [Lens] Move dataViews cache into main Lens state (#137309) * Move lens dataViews state into main state * :fire: Remove some old cruft from the code * :bug: Fix dataViews layer change * :bug: Fix datasourceLayers refs * :fire: Remove more old cruft * :bug: Fix bug when loading SO * :bug: Fix initial existence flag * :label: Fix type issues * :label: Fix types and tests * :label: Fix types issues * :white_check_mark: Fix more tests * :white_check_mark: Fix with new dataViews structure * :white_check_mark: Fix more test mocks * :white_check_mark: More tests fixed * :fire: Removed unused prop * :white_check_mark: Down to single broken test suite * :label: Fix type issue * :ok_hand: Integrate selector feedback * :white_check_mark: Fix remaining unit tests * :label: fix type issues * :bug: Fix bug when creating dataview in place * :bug: Fix edit + remove field flow * Update x-pack/plugins/lens/public/visualizations/xy/types.ts * :camera_flash: Fix snapshot * :bug: Fix the dataViews switch bug * :fire: remove old cruft Co-authored-by: Joe Reuter --- .../__snapshots__/app.test.tsx.snap | 8 + .../lens/public/app_plugin/app.test.tsx | 2 +- x-pack/plugins/lens/public/app_plugin/app.tsx | 29 +- .../lens/public/app_plugin/lens_top_nav.tsx | 128 ++- .../lens/public/app_plugin/mounter.tsx | 2 +- .../app_plugin/show_underlying_data.test.ts | 11 +- .../public/app_plugin/show_underlying_data.ts | 5 +- .../plugins/lens/public/app_plugin/types.ts | 2 + .../buttons/draggable_dimension_button.tsx | 4 + .../buttons/drop_targets_utils.test.tsx | 5 + .../buttons/empty_dimension_button.tsx | 4 + .../config_panel/config_panel.test.tsx | 19 +- .../config_panel/config_panel.tsx | 36 +- .../config_panel/layer_panel.test.tsx | 3 + .../editor_frame/config_panel/layer_panel.tsx | 101 +- .../config_panel/layer_settings.test.tsx | 1 + .../editor_frame/config_panel/types.ts | 2 + .../editor_frame/data_panel_wrapper.test.tsx | 8 +- .../editor_frame/data_panel_wrapper.tsx | 73 +- .../editor_frame/editor_frame.test.tsx | 20 +- .../editor_frame/editor_frame.tsx | 8 +- .../editor_frame/expression_helpers.ts | 12 +- .../editor_frame/state_helpers.ts | 267 ++++- .../editor_frame/suggestion_helpers.test.ts | 60 +- .../editor_frame/suggestion_helpers.ts | 21 +- .../editor_frame/suggestion_panel.tsx | 13 +- .../workspace_panel/chart_switch.tsx | 1 + .../workspace_panel/workspace_panel.tsx | 6 +- .../public/editor_frame_service/service.tsx | 30 +- .../lens/public/editor_frame_service/types.ts | 2 +- .../public/embeddable/embeddable.test.tsx | 44 +- .../lens/public/embeddable/embeddable.tsx | 32 +- .../public/embeddable/embeddable_factory.ts | 6 +- .../__mocks__/loader.ts | 22 +- .../change_indexpattern.tsx | 2 +- .../datapanel.test.tsx | 354 ++++--- .../indexpattern_datasource/datapanel.tsx | 161 ++- .../bucket_nesting_editor.test.tsx | 2 +- .../dimension_panel/bucket_nesting_editor.tsx | 3 +- .../dimension_panel/dimension_editor.tsx | 21 +- .../dimension_panel/dimension_panel.test.tsx | 124 ++- .../dimension_panel/dimension_panel.tsx | 5 +- .../droppable/get_drop_props.test.ts | 12 +- .../droppable/get_drop_props.ts | 27 +- .../dimension_panel/droppable/mocks.ts | 6 +- .../droppable/on_drop_handler.test.ts | 36 +- .../droppable/on_drop_handler.ts | 33 +- .../dimension_panel/field_input.test.tsx | 33 +- .../dimension_panel/field_input.tsx | 2 +- .../dimension_panel/field_select.tsx | 13 +- .../dimension_panel/filtering.tsx | 3 +- .../dimension_panel/operation_support.ts | 6 +- .../dimension_panel/reference_editor.tsx | 12 +- .../dimension_panel/time_shift.tsx | 5 +- .../dimension_panel/window.tsx | 3 +- .../indexpattern_datasource/document_field.ts | 2 +- .../field_item.test.tsx | 2 +- .../indexpattern_datasource/field_item.tsx | 4 +- .../indexpattern_datasource/field_list.tsx | 167 ++- .../fields_accordion.test.tsx | 2 +- .../fields_accordion.tsx | 4 +- .../public/indexpattern_datasource/index.ts | 2 +- .../indexpattern.test.ts | 334 +++--- .../indexpattern_datasource/indexpattern.tsx | 155 ++- .../indexpattern_suggestions.test.tsx | 774 ++++++++------ .../indexpattern_suggestions.ts | 111 +- .../layerpanel.test.tsx | 73 +- .../indexpattern_datasource/layerpanel.tsx | 13 +- .../indexpattern_datasource/loader.test.ts | 955 +++--------------- .../public/indexpattern_datasource/loader.ts | 464 ++------- .../public/indexpattern_datasource/mocks.ts | 2 +- .../operations/definitions.test.ts | 3 +- .../definitions/calculations/utils.ts | 3 +- .../operations/definitions/count.tsx | 2 +- .../definitions/date_histogram.test.tsx | 3 +- .../definitions/filters/filter_popover.tsx | 2 +- .../definitions/filters/filters.tsx | 4 +- .../formula/editor/formula_help.tsx | 2 +- .../formula/editor/math_completion.test.ts | 3 +- .../formula/editor/math_completion.ts | 2 +- .../definitions/formula/formula.test.tsx | 3 +- .../definitions/formula/formula.tsx | 2 +- .../formula/formula_public_api.test.ts | 4 +- .../definitions/formula/formula_public_api.ts | 5 +- .../operations/definitions/formula/math.tsx | 2 +- .../operations/definitions/formula/parse.ts | 3 +- .../definitions/formula/validation.ts | 3 +- .../operations/definitions/helpers.tsx | 3 +- .../operations/definitions/index.ts | 15 +- .../definitions/last_value.test.tsx | 3 +- .../operations/definitions/last_value.tsx | 2 +- .../definitions/percentile.test.tsx | 3 +- .../definitions/percentile_ranks.test.tsx | 3 +- .../definitions/ranges/ranges.test.tsx | 3 +- .../operations/definitions/ranges/ranges.tsx | 2 +- .../definitions/shared_components/index.tsx | 3 +- .../definitions/static_value.test.tsx | 3 +- .../operations/definitions/static_value.tsx | 2 +- .../definitions/terms/field_inputs.tsx | 8 +- .../operations/definitions/terms/helpers.ts | 6 +- .../operations/definitions/terms/index.tsx | 2 +- .../definitions/terms/terms.test.tsx | 12 +- .../operations/layer_helpers.test.ts | 3 +- .../operations/layer_helpers.ts | 4 +- .../operations/operations.ts | 3 +- .../pure_helpers.test.ts | 16 - .../indexpattern_datasource/pure_helpers.ts | 10 +- .../indexpattern_datasource/query_input.tsx | 7 +- .../time_shift_utils.tsx | 9 +- .../indexpattern_datasource/to_expression.ts | 6 +- .../public/indexpattern_datasource/types.ts | 41 +- .../indexpattern_datasource/utils.test.tsx | 12 +- .../public/indexpattern_datasource/utils.tsx | 8 +- .../indexpattern_datasource/window_utils.tsx | 3 +- .../indexpattern_service/loader.test.ts | 435 ++++++++ .../public/indexpattern_service/loader.ts | 311 ++++++ .../lens/public/indexpattern_service/mocks.ts | 220 ++++ .../public/indexpattern_service/service.ts | 118 +++ .../public/mocks/data_views_service_mock.ts | 24 + .../lens/public/mocks/datasource_mock.ts | 19 +- x-pack/plugins/lens/public/mocks/index.ts | 12 + .../lens/public/mocks/services_mock.tsx | 3 +- .../plugins/lens/public/mocks/store_mocks.tsx | 8 +- x-pack/plugins/lens/public/plugin.ts | 10 +- .../dataview_picker/dataview_picker.tsx | 93 ++ .../dataview_picker/helpers.ts | 29 + .../dataview_picker/index.ts | 9 + .../field_picker/field_picker.tsx | 2 +- .../lens/public/shared_components/index.ts | 1 + .../__snapshots__/load_initial.test.tsx.snap | 6 + .../context_middleware/index.ts | 7 +- .../lens/public/state_management/index.ts | 1 + .../init_middleware/load_initial.ts | 55 +- .../public/state_management/lens_slice.ts | 142 ++- .../state_management/load_initial.test.tsx | 10 +- .../lens/public/state_management/selectors.ts | 15 +- .../lens/public/state_management/types.ts | 17 +- x-pack/plugins/lens/public/types.ts | 132 ++- x-pack/plugins/lens/public/utils.ts | 79 +- .../xy/annotations/helpers.test.ts | 8 +- .../lens/public/visualizations/xy/index.ts | 8 +- .../visualizations/xy/to_expression.test.ts | 12 +- .../visualizations/xy/visualization.test.ts | 10 +- .../visualizations/xy/visualization.tsx | 34 +- .../visualizations/xy/xy_suggestions.test.ts | 9 +- 145 files changed, 4082 insertions(+), 2909 deletions(-) delete mode 100644 x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.test.ts create mode 100644 x-pack/plugins/lens/public/indexpattern_service/loader.test.ts create mode 100644 x-pack/plugins/lens/public/indexpattern_service/loader.ts create mode 100644 x-pack/plugins/lens/public/indexpattern_service/mocks.ts create mode 100644 x-pack/plugins/lens/public/indexpattern_service/service.ts create mode 100644 x-pack/plugins/lens/public/mocks/data_views_service_mock.ts create mode 100644 x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx create mode 100644 x-pack/plugins/lens/public/shared_components/dataview_picker/helpers.ts create mode 100644 x-pack/plugins/lens/public/shared_components/dataview_picker/index.ts diff --git a/x-pack/plugins/lens/public/app_plugin/__snapshots__/app.test.tsx.snap b/x-pack/plugins/lens/public/app_plugin/__snapshots__/app.test.tsx.snap index ca14bc908eb80d..9f65fa549e03c5 100644 --- a/x-pack/plugins/lens/public/app_plugin/__snapshots__/app.test.tsx.snap +++ b/x-pack/plugins/lens/public/app_plugin/__snapshots__/app.test.tsx.snap @@ -4,6 +4,14 @@ exports[`Lens App renders the editor frame 1`] = ` Array [ Array [ Object { + "indexPatternService": Object { + "ensureIndexPattern": [Function], + "getDefaultIndex": [Function], + "loadIndexPatternRefs": [Function], + "loadIndexPatterns": [Function], + "refreshExistingFields": [Function], + "updateDataViewsState": [Function], + }, "lensInspector": Object { "adapters": Object { "expression": ExpressionsInspectorAdapter { diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 54e1c5eda5d588..a2e247cc427c82 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -477,7 +477,7 @@ describe('Lens App', () => { expect(services.navigation.ui.TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', - indexPatterns: [{ id: 'mockip', isTimeBased: expect.any(Function) }], + indexPatterns: [{ id: 'mockip', isTimeBased: expect.any(Function), fields: [] }], }), {} ); diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx index 4f5027c908b09e..7ff105adf43f75 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.tsx @@ -25,11 +25,13 @@ import { LensAppState, DispatchSetState, selectSavedObjectFormat, + updateIndexPatterns, } from '../state_management'; import { SaveModalContainer, runSaveLensVisualization } from './save_modal_container'; import { LensInspector } from '../lens_inspector_service'; import { getEditPath } from '../../common'; import { isLensEqual } from './lens_document_equality'; +import { IndexPatternServiceAPI, createIndexPatternService } from '../indexpattern_service/service'; export type SaveProps = Omit & { returnToOrigin: boolean; @@ -66,6 +68,7 @@ export function App({ getOriginatingAppName, spaces, http, + notifications, executionContext, // Temporarily required until the 'by value' paradigm is default. dashboardFeatureFlag, @@ -360,6 +363,22 @@ export function App({ ); }, [initialContext]); + const indexPatternService = useMemo( + () => + createIndexPatternService({ + dataViews: lensAppServices.dataViews, + uiSettings: lensAppServices.uiSettings, + core: { http, notifications }, + updateIndexPatterns: (newIndexPatternsState, options) => { + dispatch(updateIndexPatterns(newIndexPatternsState)); + if (options?.applyImmediately) { + dispatch(applyChanges()); + } + }, + }), + [dispatch, http, notifications, lensAppServices] + ); + return ( <>
    @@ -381,6 +400,7 @@ export function App({ topNavMenuEntryGenerators={topNavMenuEntryGenerators} initialContext={initialContext} theme$={theme$} + indexPatternService={indexPatternService} /> {getLegacyUrlConflictCallout()} {(!isLoading || persistedDoc) && ( @@ -388,6 +408,7 @@ export function App({ editorFrame={editorFrame} showNoDataPopover={showNoDataPopover} lensInspector={lensInspector} + indexPatternService={indexPatternService} /> )}
    @@ -449,13 +470,19 @@ const MemoizedEditorFrameWrapper = React.memo(function EditorFrameWrapper({ editorFrame, showNoDataPopover, lensInspector, + indexPatternService, }: { editorFrame: EditorFrameInstance; lensInspector: LensInspector; showNoDataPopover: () => void; + indexPatternService: IndexPatternServiceAPI; }) { const { EditorFrameContainer } = editorFrame; return ( - + ); }); diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 5dd2368d2b83ac..88643b52aab776 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -15,7 +15,6 @@ import { tableHasFormulas } from '@kbn/data-plugin/common'; import { exporters, getEsQueryConfig } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { StateSetter } from '../types'; import { LensAppServices, LensTopNavActions, @@ -29,16 +28,15 @@ import { useLensDispatch, LensAppState, DispatchSetState, - updateDatasourceState, } from '../state_management'; import { getIndexPatternsObjects, getIndexPatternsIds, getResolvedDateRange, - handleIndexPatternChange, refreshIndexPatternsList, } from '../utils'; import { combineQueryAndFilters, getLayerMetaInfo } from './show_underlying_data'; +import { changeIndexPattern } from '../state_management/lens_slice'; function getLensTopNavConfig(options: { showSaveAndReturn: boolean; @@ -219,6 +217,7 @@ export const LensTopNavMenu = ({ topNavMenuEntryGenerators, initialContext, theme$, + indexPatternService, }: LensTopNavMenuProps) => { const { data, @@ -231,14 +230,59 @@ export const LensTopNavMenu = ({ dashboardFeatureFlag, dataViewFieldEditor, dataViewEditor, - dataViews, + dataViews: dataViewsService, } = useKibana().services; + const { + isSaveable, + isLinkedToOriginatingApp, + query, + activeData, + savedQuery, + activeDatasourceId, + datasourceStates, + visualization, + filters, + dataViews, + } = useLensSelector((state) => state.lens); + const dispatch = useLensDispatch(); const dispatchSetState: DispatchSetState = React.useCallback( (state: Partial) => dispatch(setState(state)), [dispatch] ); + const dispatchChangeIndexPattern = React.useCallback( + async (indexPatternId) => { + const [newIndexPatternRefs, newIndexPatterns] = await Promise.all([ + // Reload refs in case it's a new indexPattern created on the spot + dataViews.indexPatternRefs[indexPatternId] + ? dataViews.indexPatternRefs + : indexPatternService.loadIndexPatternRefs({ + isFullEditor: true, + }), + indexPatternService.ensureIndexPattern({ + id: indexPatternId, + cache: dataViews.indexPatterns, + }), + ]); + dispatch( + changeIndexPattern({ + dataViews: { indexPatterns: newIndexPatterns, indexPatternRefs: newIndexPatternRefs }, + datasourceIds: Object.keys(datasourceStates), + visualizationIds: visualization.activeId ? [visualization.activeId] : [], + indexPatternId, + }) + ); + }, + [ + dataViews.indexPatternRefs, + dataViews.indexPatterns, + datasourceStates, + dispatch, + indexPatternService, + visualization.activeId, + ] + ); const [indexPatterns, setIndexPatterns] = useState([]); const [currentIndexPattern, setCurrentIndexPattern] = useState(); @@ -247,18 +291,6 @@ export const LensTopNavMenu = ({ const closeFieldEditor = useRef<() => void | undefined>(); const closeDataViewEditor = useRef<() => void | undefined>(); - const { - isSaveable, - isLinkedToOriginatingApp, - query, - activeData, - savedQuery, - activeDatasourceId, - datasourceStates, - visualization, - filters, - } = useLensSelector((state) => state.lens); - const allLoaded = Object.values(datasourceStates).every(({ isLoading }) => isLoading === false); useEffect(() => { @@ -290,7 +322,7 @@ export const LensTopNavMenu = ({ // Update the cached index patterns if the user made a change to any of them if (hasIndexPatternsChanged) { - getIndexPatternsObjects(indexPatternIds, dataViews).then( + getIndexPatternsObjects(indexPatternIds, dataViewsService).then( ({ indexPatterns: indexPatternObjects, rejectedIds }) => { setIndexPatterns(indexPatternObjects); setRejectedIndexPatterns(rejectedIds); @@ -303,7 +335,7 @@ export const LensTopNavMenu = ({ rejectedIndexPatterns, datasourceMap, indexPatterns, - dataViews, + dataViewsService, ]); useEffect(() => { @@ -366,6 +398,7 @@ export const LensTopNavMenu = ({ datasourceMap[activeDatasourceId], datasourceStates[activeDatasourceId].state, activeData, + dataViews.indexPatterns, data.query.timefilter.timefilter.getTime(), application.capabilities ); @@ -375,6 +408,7 @@ export const LensTopNavMenu = ({ datasourceMap, datasourceStates, activeData, + dataViews.indexPatterns, data.query.timefilter.timefilter, application.capabilities, ]); @@ -604,20 +638,8 @@ export const LensTopNavMenu = ({ }); }, [data.query.filterManager, data.query.queryString, dispatchSetState]); - const setDatasourceState: StateSetter = useMemo(() => { - return (updater) => { - dispatch( - updateDatasourceState({ - updater, - datasourceId: activeDatasourceId!, - clearStagedPreview: true, - }) - ); - }; - }, [activeDatasourceId, dispatch]); - const refreshFieldList = useCallback(async () => { - if (currentIndexPattern && currentIndexPattern.id) { + if (currentIndexPattern?.id) { refreshIndexPatternsList({ activeDatasources: Object.keys(datasourceStates).reduce( (acc, datasourceId) => ({ @@ -627,7 +649,8 @@ export const LensTopNavMenu = ({ {} ), indexPatternId: currentIndexPattern.id, - setDatasourceState, + indexPatternService, + indexPatternsCache: dataViews.indexPatterns, }); } // start a new session so all charts are refreshed @@ -637,7 +660,8 @@ export const LensTopNavMenu = ({ data.search.session, datasourceMap, datasourceStates, - setDatasourceState, + indexPatternService, + dataViews.indexPatterns, ]); const editField = useMemo( @@ -679,32 +703,14 @@ export const LensTopNavMenu = ({ closeDataViewEditor.current = dataViewEditor.openEditor({ onSave: async (dataView) => { if (dataView.id) { - handleIndexPatternChange({ - activeDatasources: Object.keys(datasourceStates).reduce( - (acc, datasourceId) => ({ - ...acc, - [datasourceId]: datasourceMap[datasourceId], - }), - {} - ), - datasourceStates, - indexPatternId: dataView.id, - setDatasourceState, - }); + dispatchChangeIndexPattern(dataView.id); refreshFieldList(); } }, }); } : undefined, - [ - dataViewEditor, - canEditDataView, - datasourceMap, - datasourceStates, - refreshFieldList, - setDatasourceState, - ] + [canEditDataView, dataViewEditor, dispatchChangeIndexPattern, refreshFieldList] ); const dataViewPickerProps = { @@ -721,18 +727,7 @@ export const LensTopNavMenu = ({ (indexPattern) => indexPattern.id === newIndexPatternId ); setCurrentIndexPattern(currentDataView); - handleIndexPatternChange({ - activeDatasources: Object.keys(datasourceStates).reduce( - (acc, datasourceId) => ({ - ...acc, - [datasourceId]: datasourceMap[datasourceId], - }), - {} - ), - datasourceStates, - indexPatternId: newIndexPatternId, - setDatasourceState, - }); + dispatchChangeIndexPattern(newIndexPatternId); }, }; @@ -759,7 +754,8 @@ export const LensTopNavMenu = ({ allLoaded && activeDatasourceId && datasourceMap[activeDatasourceId].isTimeBased( - datasourceStates[activeDatasourceId].state + datasourceStates[activeDatasourceId].state, + dataViews.indexPatterns ) ) } diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 4df1d37bd52c52..34a06439473a39 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -223,7 +223,7 @@ export async function mountApp( }; const lensStore: LensRootStore = makeConfigureStore(storeDeps, { lens: getPreloadedState(storeDeps) as LensAppState, - } as PreloadedState); + } as unknown as PreloadedState); const EditorRenderer = React.memo( (props: { id?: string; history: History; editByValue?: boolean }) => { diff --git a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.test.ts b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.test.ts index 99bc4fa0f9717b..8a8c7bbe1f9730 100644 --- a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.test.ts +++ b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.test.ts @@ -21,6 +21,7 @@ describe('getLayerMetaInfo', () => { createMockDatasource('testDatasource'), {}, undefined, + {}, undefined, capabilities ).error @@ -36,6 +37,7 @@ describe('getLayerMetaInfo', () => { datatable1: { type: 'datatable', columns: [], rows: [] }, datatable2: { type: 'datatable', columns: [], rows: [] }, }, + {}, undefined, capabilities ).error @@ -43,7 +45,7 @@ describe('getLayerMetaInfo', () => { }); it('should return error in case of missing activeDatasource', () => { - expect(getLayerMetaInfo(undefined, {}, undefined, undefined, capabilities).error).toBe( + expect(getLayerMetaInfo(undefined, {}, undefined, {}, undefined, capabilities).error).toBe( 'Visualization has no data available to show' ); }); @@ -54,6 +56,7 @@ describe('getLayerMetaInfo', () => { createMockDatasource('testDatasource'), undefined, {}, + {}, undefined, capabilities ).error @@ -81,7 +84,7 @@ describe('getLayerMetaInfo', () => { }; mockDatasource.getPublicAPI.mockReturnValue(updatedPublicAPI); expect( - getLayerMetaInfo(createMockDatasource('testDatasource'), {}, {}, undefined, capabilities) + getLayerMetaInfo(createMockDatasource('testDatasource'), {}, {}, {}, undefined, capabilities) .error ).toBe('Visualization has no data available to show'); }); @@ -105,6 +108,7 @@ describe('getLayerMetaInfo', () => { { datatable1: { type: 'datatable', columns: [], rows: [] }, }, + {}, undefined, capabilities ).error @@ -120,6 +124,7 @@ describe('getLayerMetaInfo', () => { { datatable1: { type: 'datatable', columns: [], rows: [] }, }, + {}, undefined, { navLinks: { discover: false }, @@ -134,6 +139,7 @@ describe('getLayerMetaInfo', () => { { datatable1: { type: 'datatable', columns: [], rows: [] }, }, + {}, undefined, { navLinks: { discover: true }, @@ -167,6 +173,7 @@ describe('getLayerMetaInfo', () => { { datatable1: { type: 'datatable', columns: [], rows: [] }, }, + {}, undefined, capabilities ); diff --git a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts index e678ad5ddf00db..0390b516bcd4ab 100644 --- a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts +++ b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts @@ -21,7 +21,7 @@ import { Capabilities } from '@kbn/core/public'; import { partition } from 'lodash'; import { showMemoizedErrorNotification } from '../lens_ui_errors'; import { TableInspectorAdapter } from '../editor_frame_service/types'; -import { Datasource, DatasourcePublicAPI } from '../types'; +import { Datasource, DatasourcePublicAPI, IndexPatternMap } from '../types'; /** * Joins a series of queries. @@ -62,6 +62,7 @@ export function getLayerMetaInfo( currentDatasource: Datasource | undefined, datasourceState: unknown, activeData: TableInspectorAdapter | undefined, + indexPatterns: IndexPatternMap, timeRange: TimeRange | undefined, capabilities: RecursiveReadonly<{ navLinks: Capabilities['navLinks']; @@ -90,7 +91,6 @@ export function getLayerMetaInfo( isVisible, }; } - let datasourceAPI: DatasourcePublicAPI; try { @@ -98,6 +98,7 @@ export function getLayerMetaInfo( datasourceAPI = currentDatasource.getPublicAPI({ layerId: firstLayerId, state: datasourceState, + indexPatterns, }); } catch (error) { showMemoizedErrorNotification(error); diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index abb6cfa6a06a6e..6a2718fc498203 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -47,6 +47,7 @@ import type { import type { LensAttributeService } from '../lens_attribute_service'; import type { LensEmbeddableInput } from '../embeddable/embeddable'; import type { LensInspector } from '../lens_inspector_service'; +import { IndexPatternServiceAPI } from '../indexpattern_service/service'; export interface RedirectToOriginProps { input?: LensEmbeddableInput; @@ -107,6 +108,7 @@ export interface LensTopNavMenuProps { topNavMenuEntryGenerators: LensTopNavMenuEntryGenerator[]; initialContext?: VisualizeFieldContext | VisualizeEditorContext; theme$: Observable; + indexPatternService: IndexPatternServiceAPI; } export interface HistoryLocationState { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx index 45dcda4b607ff7..a118183c49061a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx @@ -13,6 +13,7 @@ import { isOperation, DropType, DatasourceLayers, + IndexPatternMap, } from '../../../../types'; import { getCustomDropTarget, @@ -37,6 +38,7 @@ export function DraggableDimensionButton({ layerDatasource, datasourceLayers, registerNewButtonRef, + indexPatterns, }: { layerId: string; groupIndex: number; @@ -53,6 +55,7 @@ export function DraggableDimensionButton({ accessorIndex: number; columnId: string; registerNewButtonRef: (id: string, instance: HTMLDivElement | null) => void; + indexPatterns: IndexPatternMap; }) { const { dragging } = useContext(DragContext); @@ -73,6 +76,7 @@ export function DraggableDimensionButton({ filterOperations: group.filterOperations, prioritizedOperation: group.prioritizedOperation, }, + indexPatterns, }, sharedDatasource ); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx index dd5ec847fb5b5c..17907ac19c4bc3 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx @@ -27,6 +27,7 @@ describe('getDropProps', () => { id: 'annotationColumn2', humanData: { label: 'Event' }, }, + indexPatterns: {}, }, mockDatasource ); @@ -50,6 +51,7 @@ describe('getDropProps', () => { id: 'annotationColumn2', humanData: { label: 'Event' }, }, + indexPatterns: {}, }) ).toEqual({ dropTypes: ['reorder'] }); }); @@ -71,6 +73,7 @@ describe('getDropProps', () => { id: 'annotationColumn2', humanData: { label: 'Event' }, }, + indexPatterns: {}, }) ).toEqual({ dropTypes: ['duplicate_compatible'] }); }); @@ -91,6 +94,7 @@ describe('getDropProps', () => { id: 'annotationColumn2', humanData: { label: 'Event' }, }, + indexPatterns: {}, }) ).toEqual({ dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], @@ -114,6 +118,7 @@ describe('getDropProps', () => { id: 'annotationColumn2', humanData: { label: 'Event' }, }, + indexPatterns: {}, }) ).toEqual({ dropTypes: ['move_compatible', 'duplicate_compatible'], diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx index 8ef2754ef94aea..b6d7e58b0f7e76 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx @@ -18,6 +18,7 @@ import { DropType, DatasourceLayers, isOperation, + IndexPatternMap, } from '../../../../types'; import { getCustomDropTarget, @@ -111,6 +112,7 @@ export function EmptyDimensionButton({ onClick, onDrop, datasourceLayers, + indexPatterns, }: { layerId: string; groupIndex: number; @@ -121,6 +123,7 @@ export function EmptyDimensionButton({ layerDatasource?: Datasource; datasourceLayers: DatasourceLayers; state: unknown; + indexPatterns: IndexPatternMap; }) { const { dragging } = useContext(DragContext); const sharedDatasource = @@ -148,6 +151,7 @@ export function EmptyDimensionButton({ prioritizedOperation: group.prioritizedOperation, isNewColumn: true, }, + indexPatterns, }, sharedDatasource ); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx index a13b6b480a9008..5c1b5c4d9d8a64 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx @@ -25,6 +25,7 @@ import { mountWithProvider } from '../../../mocks'; import { LayerType, layerTypes } from '../../../../common'; import { ReactWrapper } from 'enzyme'; import { addLayer } from '../../../state_management'; +import { createIndexPatternServiceMock } from '../../../mocks/data_views_service_mock'; jest.mock('../../../id_generator'); @@ -107,6 +108,7 @@ describe('ConfigPanel', () => { state: 'state', }, }, + indexPatternService: createIndexPatternServiceMock(), visualizationState: 'state', updateVisualization: jest.fn(), updateDatasource: jest.fn(), @@ -354,11 +356,16 @@ describe('ConfigPanel', () => { await clickToAddLayer(instance); expect(lensStore.dispatch).toHaveBeenCalledTimes(1); - expect(datasourceMap.testDatasource.initializeDimension).toHaveBeenCalledWith({}, 'newId', { - columnId: 'myColumn', - groupId: 'testGroup', - staticValue: 100, - }); + expect(datasourceMap.testDatasource.initializeDimension).toHaveBeenCalledWith( + {}, + 'newId', + frame.dataViews.indexPatterns, + { + columnId: 'myColumn', + groupId: 'testGroup', + staticValue: 100, + } + ); }); it('should add an initial dimension value when clicking on the empty dimension button', async () => { @@ -388,6 +395,7 @@ describe('ConfigPanel', () => { expect(datasourceMap.testDatasource.initializeDimension).toHaveBeenCalledWith( 'state', 'first', + frame.dataViews.indexPatterns, { groupId: 'a', columnId: 'newId', @@ -445,6 +453,7 @@ describe('ConfigPanel', () => { a: expect.anything(), }, dateRange: expect.anything(), + dataViews: expect.anything(), }, groupId: 'a', layerId: 'newId', diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx index b23eefa2e56cda..7acfba1bdcb79b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React, { useMemo, memo } from 'react'; +import React, { useMemo, memo, useCallback } from 'react'; import { EuiForm } from '@elastic/eui'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { UPDATE_FILTER_REFERENCES_ACTION, UPDATE_FILTER_REFERENCES_TRIGGER, } from '@kbn/unified-search-plugin/public'; +import { changeIndexPattern } from '../../../state_management/lens_slice'; import { Visualization } from '../../../types'; import { LayerPanel } from './layer_panel'; import { generateId } from '../../../id_generator'; @@ -49,7 +50,7 @@ export function LayerPanels( activeVisualization: Visualization; } ) { - const { activeVisualization, datasourceMap } = props; + const { activeVisualization, datasourceMap, indexPatternService } = props; const { activeDatasourceId, visualization, datasourceStates } = useLensSelector( (state) => state.lens ); @@ -154,6 +155,35 @@ export function LayerPanels( [dispatchLens] ); + const onChangeIndexPattern = useCallback( + async ({ + indexPatternId, + datasourceId, + visualizationId, + layerId, + }: { + indexPatternId: string; + datasourceId?: string; + visualizationId?: string; + layerId?: string; + }) => { + const indexPatterns = await props.indexPatternService.ensureIndexPattern({ + id: indexPatternId, + cache: props.framePublicAPI.dataViews.indexPatterns, + }); + dispatchLens( + changeIndexPattern({ + indexPatternId, + datasourceIds: datasourceId ? [datasourceId] : [], + visualizationIds: visualizationId ? [visualizationId] : [], + layerId, + dataViews: { indexPatterns }, + }) + ); + }, + [dispatchLens, props.framePublicAPI.dataViews, props.indexPatternService] + ); + return ( {layerIds.map((layerId, layerIndex) => ( @@ -168,6 +198,7 @@ export function LayerPanels( updateVisualization={setVisualizationState} updateDatasource={updateDatasource} updateDatasourceAsync={updateDatasourceAsync} + onChangeIndexPattern={onChangeIndexPattern} updateAll={updateAll} isOnlyLayer={ getRemoveOperation( @@ -222,6 +253,7 @@ export function LayerPanels( removeLayerRef(layerId); }} toggleFullscreen={toggleFullscreen} + indexPatternService={indexPatternService} /> ))} { isFullscreen: false, toggleFullscreen: jest.fn(), onEmptyDimensionAdd: jest.fn(), + onChangeIndexPattern: jest.fn(), + indexPatternService: createIndexPatternServiceMock(), }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index 562e7867d0e3a5..86e896c29910c3 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -18,6 +18,7 @@ import { EuiIconTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { IndexPatternServiceAPI } from '../../../indexpattern_service/service'; import { NativeRenderer } from '../../../native_renderer'; import { StateSetter, @@ -65,6 +66,13 @@ export function LayerPanel( registerNewLayerRef: (layerId: string, instance: HTMLDivElement | null) => void; toggleFullscreen: () => void; onEmptyDimensionAdd: (columnId: string, group: { groupId: string }) => void; + onChangeIndexPattern: (args: { + indexPatternId: string; + layerId: string; + datasourceId?: string; + visualizationId?: string; + }) => void; + indexPatternService: IndexPatternServiceAPI; } ) { const [activeDimension, setActiveDimension] = useState( @@ -86,6 +94,7 @@ export function LayerPanel( updateAll, updateDatasourceAsync, visualizationState, + onChangeIndexPattern, } = props; const datasourceStates = useLensSelector(selectDatasourceStates); @@ -186,6 +195,7 @@ export function LayerPanel( }, dimensionGroups: groups, dropType, + indexPatterns: framePublicAPI.dataViews.indexPatterns, }) ); } @@ -209,15 +219,15 @@ export function LayerPanel( }; }, [ layerDatasource, - layerDatasourceState, setNextFocusedButtonId, + layerDatasourceState, groups, + updateDatasource, + datasourceId, activeVisualization, + updateVisualization, props.visualizationState, framePublicAPI, - updateVisualization, - datasourceId, - updateDatasource, ]); const isDimensionPanelOpen = Boolean(activeId); @@ -293,6 +303,8 @@ export function LayerPanel( ] ); + const { dataViews } = props.framePublicAPI; + return ( <>
    @@ -304,6 +316,12 @@ export function LayerPanel( layerConfigProps={{ ...layerVisualizationConfigProps, setState: props.updateVisualization, + onChangeIndexPattern: (indexPatternId) => + onChangeIndexPattern({ + indexPatternId, + layerId, + visualizationId: activeVisualization.id, + }), }} activeVisualization={activeVisualization} /> @@ -318,45 +336,36 @@ export function LayerPanel( /> + {(layerDatasource || activeVisualization.renderLayerPanel) && } {layerDatasource && ( - <> - - { - const newState = - typeof updater === 'function' ? updater(layerDatasourceState) : updater; - // Look for removed columns - const nextPublicAPI = layerDatasource.getPublicAPI({ - state: newState, - layerId, - }); - const nextTable = new Set( - nextPublicAPI.getTableSpec().map(({ columnId }) => columnId) - ); - const removed = datasourcePublicAPI - ?.getTableSpec() - .map(({ columnId }) => columnId) - .filter((columnId) => !nextTable.has(columnId)); - let nextVisState = props.visualizationState; - removed?.forEach((columnId) => { - nextVisState = activeVisualization.removeDimension({ - layerId, - columnId, - prevState: nextVisState, - frame: framePublicAPI, - }); - }); - - props.updateAll(datasourceId, newState, nextVisState); - }, - }} - /> - + + onChangeIndexPattern({ indexPatternId, layerId, datasourceId }), + }} + /> + )} + {activeVisualization.renderLayerPanel && ( + + onChangeIndexPattern({ + indexPatternId, + layerId, + visualizationId: activeVisualization.id, + }), + }} + /> )} @@ -441,6 +450,7 @@ export function LayerPanel( onDragStart={() => setHideTooltip(true)} onDragEnd={() => setHideTooltip(false)} onDrop={onDrop} + indexPatterns={dataViews.indexPatterns} >
    ) : ( @@ -541,6 +555,7 @@ export function LayerPanel( }); }} onDrop={onDrop} + indexPatterns={dataViews.indexPatterns} /> ) : null} @@ -601,6 +616,8 @@ export function LayerPanel( paramEditorCustomProps: activeGroup.paramEditorCustomProps, supportFieldFormat: activeGroup.supportFieldFormat !== false, layerType: activeVisualization.getLayerType(layerId, visualizationState), + indexPatterns: dataViews.indexPatterns, + existingFields: dataViews.existingFields, activeData: layerVisualizationConfigProps.activeData, }} /> diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx index 04c430143a3c8e..3daea87dad39d3 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_settings.test.tsx @@ -28,6 +28,7 @@ describe('LayerSettings', () => { dateRange: { fromDate: 'now-7d', toDate: 'now' }, activeData: frame.activeData, setState: jest.fn(), + onChangeIndexPattern: jest.fn(), }, }; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts index bafa5b73a1d71c..3e1458d42c438e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts @@ -6,6 +6,7 @@ */ import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { IndexPatternServiceAPI } from '../../../indexpattern_service/service'; import { Visualization, @@ -20,6 +21,7 @@ export interface ConfigPanelWrapperProps { datasourceMap: DatasourceMap; visualizationMap: VisualizationMap; core: DatasourceDimensionEditorProps['core']; + indexPatternService: IndexPatternServiceAPI; uiActions: UiActionsStart; } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.test.tsx index cd7d325d5830dc..63e4f88d6d2346 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.test.tsx @@ -10,9 +10,11 @@ import { DataPanelWrapper } from './data_panel_wrapper'; import { Datasource, DatasourceDataPanelProps } from '../../types'; import { DragDropIdentifier } from '../../drag_drop'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { mockStoreDeps, mountWithProvider } from '../../mocks'; +import { createMockFramePublicAPI, mockStoreDeps, mountWithProvider } from '../../mocks'; import { disableAutoApply } from '../../state_management/lens_slice'; import { selectTriggerApplyChanges } from '../../state_management'; +import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import { createIndexPatternServiceMock } from '../../mocks/data_views_service_mock'; describe('Data Panel Wrapper', () => { describe('Datasource data panel properties', () => { @@ -34,7 +36,9 @@ describe('Data Panel Wrapper', () => { core={{} as DatasourceDataPanelProps['core']} dropOntoWorkspace={(field: DragDropIdentifier) => {}} hasSuggestionForField={(field: DragDropIdentifier) => true} - plugins={{ uiActions: {} as UiActionsStart }} + plugins={{ uiActions: {} as UiActionsStart, dataViews: {} as DataViewsPublicPluginStart }} + indexPatternService={createIndexPatternServiceMock()} + frame={createMockFramePublicAPI()} />, { preloadedState: { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.tsx index 16bc0814a99167..553a61ba2c1c55 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/data_panel_wrapper.tsx @@ -7,14 +7,16 @@ import './data_panel_wrapper.scss'; -import React, { useMemo, memo, useContext, useState, useEffect } from 'react'; +import React, { useMemo, memo, useContext, useState, useEffect, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiPopover, EuiButtonIcon, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { Easteregg } from './easteregg'; import { NativeRenderer } from '../../native_renderer'; import { DragContext, DragDropIdentifier } from '../../drag_drop'; -import { StateSetter, DatasourceDataPanelProps, DatasourceMap } from '../../types'; +import { StateSetter, DatasourceDataPanelProps, DatasourceMap, FramePublicAPI } from '../../types'; import { switchDatasource, useLensDispatch, @@ -26,7 +28,10 @@ import { selectActiveDatasourceId, selectDatasourceStates, } from '../../state_management'; -import { initializeDatasources } from './state_helpers'; +import { initializeSources } from './state_helpers'; +import type { IndexPatternServiceAPI } from '../../indexpattern_service/service'; +import { changeIndexPattern } from '../../state_management/lens_slice'; +import { getInitialDataViewsObject } from '../../utils'; interface DataPanelWrapperProps { datasourceMap: DatasourceMap; @@ -34,7 +39,9 @@ interface DataPanelWrapperProps { core: DatasourceDataPanelProps['core']; dropOntoWorkspace: (field: DragDropIdentifier) => void; hasSuggestionForField: (field: DragDropIdentifier) => boolean; - plugins: { uiActions: UiActionsStart }; + plugins: { uiActions: UiActionsStart; dataViews: DataViewsPublicPluginStart }; + indexPatternService: IndexPatternServiceAPI; + frame: FramePublicAPI; } export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => { @@ -64,10 +71,21 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => { useEffect(() => { if (activeDatasourceId && datasourceStates[activeDatasourceId].state === null) { - initializeDatasources(props.datasourceMap, datasourceStates, undefined, undefined, { - isFullEditor: true, - }).then((result) => { - const newDatasourceStates = Object.entries(result).reduce( + initializeSources( + { + datasourceMap: props.datasourceMap, + datasourceStates, + dataViews: props.plugins.dataViews, + references: undefined, + initialContext: undefined, + storage: new Storage(localStorage), + defaultIndexPatternId: props.core.uiSettings.get('defaultIndex'), + }, + { + isFullEditor: true, + } + ).then(({ states, indexPatterns, indexPatternRefs }) => { + const newDatasourceStates = Object.entries(states).reduce( (state, [datasourceId, datasourceState]) => ({ ...state, [datasourceId]: { @@ -77,10 +95,42 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => { }), {} ); - dispatchLens(setState({ datasourceStates: newDatasourceStates })); + dispatchLens( + setState({ + datasourceStates: newDatasourceStates, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + }) + ); }); } - }, [datasourceStates, activeDatasourceId, props.datasourceMap, dispatchLens]); + }, [ + datasourceStates, + activeDatasourceId, + props.datasourceMap, + dispatchLens, + props.plugins.dataViews, + props.core.uiSettings, + ]); + + const onChangeIndexPattern = useCallback( + async (indexPatternId: string, datasourceId: string, layerId?: string) => { + // reload the indexpattern + const indexPatterns = await props.indexPatternService.ensureIndexPattern({ + id: indexPatternId, + cache: props.frame.dataViews.indexPatterns, + }); + // now update the state + dispatchLens( + changeIndexPattern({ + dataViews: { indexPatterns }, + datasourceIds: [datasourceId], + indexPatternId, + layerId, + }) + ); + }, + [props.indexPatternService, props.frame.dataViews.indexPatterns, dispatchLens] + ); const datasourceProps: DatasourceDataPanelProps = { ...externalContext, @@ -92,6 +142,9 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => { dropOntoWorkspace: props.dropOntoWorkspace, hasSuggestionForField: props.hasSuggestionForField, uiActions: props.plugins.uiActions, + onChangeIndexPattern, + indexPatternService: props.indexPatternService, + frame: props.frame, }; const [showDatasourceSwitcher, setDatasourceSwitcher] = useState(false); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index 047d8b4deffaa5..8d4cbade98e416 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -49,6 +49,8 @@ import { mockDataPlugin, mountWithProvider } from '../../mocks'; import { setState } from '../../state_management'; import { getLensInspectorService } from '../../lens_inspector_service'; import { toExpression } from '@kbn/interpreter'; +import { createIndexPatternServiceMock } from '../../mocks/data_views_service_mock'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; function generateSuggestion(state = {}): DatasourceSuggestion { return { @@ -63,6 +65,17 @@ function generateSuggestion(state = {}): DatasourceSuggestion { }; } +function wrapDataViewsContract() { + const dataViewsContract = dataViewPluginMocks.createStartContract(); + return { + ...dataViewsContract, + getIdsWithTitle: jest.fn(async () => [ + { id: '1', title: 'IndexPatternTitle' }, + { id: '2', title: 'OtherIndexPatternTitle' }, + ]), + }; +} + function getDefaultProps() { const defaultProps = { store: { @@ -80,10 +93,12 @@ function getDefaultProps() { data: mockDataPlugin(), expressions: expressionsPluginMock.createStartContract(), charts: chartPluginMock.createStartContract(), + dataViews: wrapDataViewsContract(), }, palettes: chartPluginMock.createPaletteRegistry(), lensInspector: getLensInspectorService(inspectorPluginMock.createStartContract()), showNoDataPopover: jest.fn(), + indexPatternService: createIndexPatternServiceMock(), }; return defaultProps; } @@ -386,7 +401,7 @@ describe('editor_frame', () => { describe('datasource public api communication', () => { it('should give access to the datasource state in the datasource factory function', async () => { const datasourceState = {}; - mockDatasource.initialize.mockResolvedValue(datasourceState); + mockDatasource.initialize.mockReturnValue(datasourceState); mockDatasource.getLayers.mockReturnValue(['first']); const props = { @@ -414,6 +429,7 @@ describe('editor_frame', () => { expect(mockDatasource.getPublicAPI).toHaveBeenCalledWith({ state: datasourceState, layerId: 'first', + indexPatterns: {}, }); }); }); @@ -499,7 +515,7 @@ describe('editor_frame', () => { it('should call datasource render with new state on switch', async () => { const initialState = {}; - mockDatasource2.initialize.mockResolvedValue(initialState); + mockDatasource2.initialize.mockReturnValue(initialState); instance.find('button[data-test-subj="datasource-switch"]').simulate('click'); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx index 5f4845e46ce3f7..f2cef399b49e88 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.tsx @@ -29,6 +29,7 @@ import { } from '../../state_management'; import type { LensInspector } from '../../lens_inspector_service'; import { ErrorBoundary, showMemoizedErrorNotification } from '../../lens_ui_errors'; +import { IndexPatternServiceAPI } from '../../indexpattern_service/service'; export interface EditorFrameProps { datasourceMap: DatasourceMap; @@ -38,6 +39,7 @@ export interface EditorFrameProps { plugins: EditorFrameStartPlugins; showNoDataPopover: () => void; lensInspector: LensInspector; + indexPatternService: IndexPatternServiceAPI; } export function EditorFrame(props: EditorFrameProps) { @@ -67,7 +69,8 @@ export function EditorFrame(props: EditorFrameProps) { datasourceStates, visualizationMap, datasourceMap[activeDatasourceId], - field + field, + framePublicAPI.dataViews ); }; @@ -103,6 +106,8 @@ export function EditorFrame(props: EditorFrameProps) { showNoDataPopover={props.showNoDataPopover} dropOntoWorkspace={dropOntoWorkspace} hasSuggestionForField={hasSuggestionForField} + indexPatternService={props.indexPatternService} + frame={framePublicAPI} /> } @@ -115,6 +120,7 @@ export function EditorFrame(props: EditorFrameProps) { visualizationMap={visualizationMap} framePublicAPI={framePublicAPI} uiActions={props.plugins.uiActions} + indexPatternService={props.indexPatternService} /> ) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts index 367d156929714a..f1caa66ede1a2c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts @@ -7,11 +7,12 @@ import { Ast, fromExpression } from '@kbn/interpreter'; import { DatasourceStates } from '../../state_management'; -import { Visualization, DatasourceMap, DatasourceLayers } from '../../types'; +import { Visualization, DatasourceMap, DatasourceLayers, IndexPatternMap } from '../../types'; export function getDatasourceExpressionsByLayers( datasourceMap: DatasourceMap, - datasourceStates: DatasourceStates + datasourceStates: DatasourceStates, + indexPatterns: IndexPatternMap ): null | Record { const datasourceExpressions: Array<[string, Ast | string]> = []; @@ -24,7 +25,7 @@ export function getDatasourceExpressionsByLayers( const layers = datasource.getLayers(state); layers.forEach((layerId) => { - const result = datasource.toExpression(state, layerId); + const result = datasource.toExpression(state, layerId, indexPatterns); if (result) { datasourceExpressions.push([layerId, result]); } @@ -52,6 +53,7 @@ export function buildExpression({ datasourceLayers, title, description, + indexPatterns, }: { title?: string; description?: string; @@ -60,6 +62,7 @@ export function buildExpression({ datasourceMap: DatasourceMap; datasourceStates: DatasourceStates; datasourceLayers: DatasourceLayers; + indexPatterns: IndexPatternMap; }): Ast | null { if (visualization === null) { return null; @@ -67,7 +70,8 @@ export function buildExpression({ const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( datasourceMap, - datasourceStates + datasourceStates, + indexPatterns ); const visualizationExpression = visualization.toExpression( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts index b4f00f273cd2d7..cfb3e5d96dd9c6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts @@ -5,15 +5,21 @@ * 2.0. */ -import { SavedObjectReference } from '@kbn/core/public'; +import { IUiSettingsClient, SavedObjectReference } from '@kbn/core/public'; import { Ast } from '@kbn/interpreter'; import memoizeOne from 'memoize-one'; import { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; +import { difference } from 'lodash'; +import type { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { Datasource, DatasourceLayers, DatasourceMap, FramePublicAPI, + IndexPattern, + IndexPatternMap, + IndexPatternRef, InitializationOptions, Visualization, VisualizationMap, @@ -23,45 +29,192 @@ import { buildExpression } from './expression_helpers'; import { showMemoizedErrorNotification } from '../../lens_ui_errors'; import { Document } from '../../persistence/saved_object_store'; import { getActiveDatasourceIdFromDoc } from '../../utils'; -import { ErrorMessage } from '../types'; +import type { ErrorMessage } from '../types'; import { getMissingCurrentDatasource, getMissingIndexPatterns, getMissingVisualizationTypeError, getUnknownVisualizationTypeError, } from '../error_helper'; -import { DatasourceStates } from '../../state_management'; +import type { DatasourceStates, DataViewsState } from '../../state_management'; +import { readFromStorage } from '../../settings_storage'; +import { loadIndexPatternRefs, loadIndexPatterns } from '../../indexpattern_service/loader'; -export async function initializeDatasources( - datasourceMap: DatasourceMap, - datasourceStates: DatasourceStates, +function getIndexPatterns( references?: SavedObjectReference[], initialContext?: VisualizeFieldContext | VisualizeEditorContext, - options?: InitializationOptions + initialId?: string ) { - const states: DatasourceStates = {}; - await Promise.all( - Object.entries(datasourceMap).map(([datasourceId, datasource]) => { - if (datasourceStates[datasourceId]) { - return datasource - .initialize( - datasourceStates[datasourceId].state || undefined, - references, - initialContext, - options - ) - .then((datasourceState) => { - states[datasourceId] = { isLoading: false, state: datasourceState }; - }); + const indexPatternIds = []; + if (initialContext) { + if ('isVisualizeAction' in initialContext) { + for (const { indexPatternId } of initialContext.layers) { + indexPatternIds.push(indexPatternId); + } + } else { + indexPatternIds.push(initialContext.indexPatternId); + } + } else { + // use the initialId only when no context is passed over + if (initialId) { + indexPatternIds.push(initialId); + } + } + if (references) { + for (const reference of references) { + if (reference.type === 'index-pattern') { + indexPatternIds.push(reference.id); } - }) + } + } + return [...new Set(indexPatternIds)]; +} + +const getLastUsedIndexPatternId = ( + storage: IStorageWrapper, + indexPatternRefs: IndexPatternRef[] +) => { + const indexPattern = readFromStorage(storage, 'indexPatternId'); + return indexPattern && indexPatternRefs.find((i) => i.id === indexPattern)?.id; +}; + +export async function initializeDataViews( + { + dataViews, + datasourceMap, + datasourceStates, + storage, + defaultIndexPatternId, + references, + initialContext, + }: { + dataViews: DataViewsContract; + datasourceMap: DatasourceMap; + datasourceStates: DatasourceStates; + defaultIndexPatternId: string; + storage: IStorageWrapper; + references?: SavedObjectReference[]; + initialContext?: VisualizeFieldContext | VisualizeEditorContext; + }, + options?: InitializationOptions +) { + const { isFullEditor } = options ?? {}; + // make it explicit or TS will infer never[] and break few lines down + const indexPatternRefs: IndexPatternRef[] = await (isFullEditor + ? loadIndexPatternRefs(dataViews) + : []); + + // if no state is available, use the fallbackId + const lastUsedIndexPatternId = getLastUsedIndexPatternId(storage, indexPatternRefs); + const fallbackId = lastUsedIndexPatternId || defaultIndexPatternId || indexPatternRefs[0]?.id; + const initialId = + !initialContext && + Object.keys(datasourceMap).every((datasourceId) => !datasourceStates[datasourceId]?.state) + ? fallbackId + : undefined; + + const usedIndexPatterns = getIndexPatterns(references, initialContext, initialId); + + // load them + const availableIndexPatterns = new Set(indexPatternRefs.map(({ id }: IndexPatternRef) => id)); + + const notUsedPatterns: string[] = difference([...availableIndexPatterns], usedIndexPatterns); + + const indexPatterns = await loadIndexPatterns({ + dataViews, + patterns: usedIndexPatterns, + notUsedPatterns, + cache: {}, + }); + + return { indexPatternRefs, indexPatterns }; +} + +/** + * This function composes both initializeDataViews & initializeDatasources into a single call + */ +export async function initializeSources( + { + dataViews, + datasourceMap, + datasourceStates, + storage, + defaultIndexPatternId, + references, + initialContext, + }: { + dataViews: DataViewsContract; + datasourceMap: DatasourceMap; + datasourceStates: DatasourceStates; + defaultIndexPatternId: string; + storage: IStorageWrapper; + references?: SavedObjectReference[]; + initialContext?: VisualizeFieldContext | VisualizeEditorContext; + }, + options?: InitializationOptions +) { + const { indexPatternRefs, indexPatterns } = await initializeDataViews( + { + datasourceMap, + datasourceStates, + initialContext, + dataViews, + storage, + defaultIndexPatternId, + references, + }, + options ); + return { + indexPatterns, + indexPatternRefs, + states: initializeDatasources({ + datasourceMap, + datasourceStates, + initialContext, + indexPatternRefs, + indexPatterns, + references, + }), + }; +} + +export function initializeDatasources({ + datasourceMap, + datasourceStates, + indexPatternRefs, + indexPatterns, + references, + initialContext, +}: { + datasourceMap: DatasourceMap; + datasourceStates: DatasourceStates; + indexPatterns: Record; + indexPatternRefs: IndexPatternRef[]; + references?: SavedObjectReference[]; + initialContext?: VisualizeFieldContext | VisualizeEditorContext; +}) { + // init datasources + const states: DatasourceStates = {}; + for (const [datasourceId, datasource] of Object.entries(datasourceMap)) { + if (datasourceStates[datasourceId]) { + const state = datasource.initialize( + datasourceStates[datasourceId].state || undefined, + references, + initialContext, + indexPatternRefs, + indexPatterns + ); + states[datasourceId] = { isLoading: false, state }; + } + } return states; } export const getDatasourceLayers = memoizeOne(function getDatasourceLayers( datasourceStates: DatasourceStates, - datasourceMap: DatasourceMap + datasourceMap: DatasourceMap, + indexPatterns: DataViewsState['indexPatterns'] ) { const datasourceLayers: DatasourceLayers = {}; Object.keys(datasourceMap) @@ -75,6 +228,7 @@ export const getDatasourceLayers = memoizeOne(function getDatasourceLayers( datasourceLayers[layer] = datasourceMap[id].getPublicAPI({ state: datasourceState, layerId: layer, + indexPatterns, }); }); }); @@ -84,7 +238,12 @@ export const getDatasourceLayers = memoizeOne(function getDatasourceLayers( export async function persistedStateToExpression( datasourceMap: DatasourceMap, visualizations: VisualizationMap, - doc: Document + doc: Document, + services: { + uiSettings: IUiSettingsClient; + storage: IStorageWrapper; + dataViews: DataViewsContract; + } ): Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }> { const { state: { visualization: visualizationState, datasourceStates: persistedDatasourceStates }, @@ -106,20 +265,32 @@ export async function persistedStateToExpression( }; } const visualization = visualizations[visualizationType!]; - const datasourceStates = await initializeDatasources( - datasourceMap, - Object.fromEntries( - Object.entries(persistedDatasourceStates).map(([id, state]) => [ - id, - { isLoading: false, state }, - ]) - ), - references, - undefined, + const datasourceStatesFromSO = Object.fromEntries( + Object.entries(persistedDatasourceStates).map(([id, state]) => [ + id, + { isLoading: false, state }, + ]) + ); + const { indexPatterns, indexPatternRefs } = await initializeDataViews( + { + datasourceMap, + datasourceStates: datasourceStatesFromSO, + references, + dataViews: services.dataViews, + storage: services.storage, + defaultIndexPatternId: services.uiSettings.get('defaultIndex'), + }, { isFullEditor: false } ); + const datasourceStates = initializeDatasources({ + datasourceMap, + datasourceStates: datasourceStatesFromSO, + references, + indexPatterns, + indexPatternRefs, + }); - const datasourceLayers = getDatasourceLayers(datasourceStates, datasourceMap); + const datasourceLayers = getDatasourceLayers(datasourceStates, datasourceMap, indexPatterns); const datasourceId = getActiveDatasourceIdFromDoc(doc); if (datasourceId == null) { @@ -131,7 +302,8 @@ export async function persistedStateToExpression( const indexPatternValidation = validateRequiredIndexPatterns( datasourceMap[datasourceId], - datasourceStates[datasourceId] + datasourceStates[datasourceId], + indexPatterns ); if (indexPatternValidation) { @@ -146,7 +318,7 @@ export async function persistedStateToExpression( datasourceStates[datasourceId].state, visualization, visualizationState, - { datasourceLayers } + { datasourceLayers, dataViews: { indexPatterns } as DataViewsState } ); return { @@ -158,6 +330,7 @@ export async function persistedStateToExpression( datasourceMap, datasourceStates, datasourceLayers, + indexPatterns, }), errors: validationResult, }; @@ -165,12 +338,13 @@ export async function persistedStateToExpression( export function getMissingIndexPattern( currentDatasource: Datasource | null, - currentDatasourceState: { state: unknown } | null + currentDatasourceState: { state: unknown } | null, + indexPatterns: IndexPatternMap ) { if (currentDatasourceState == null || currentDatasource == null) { return []; } - const missingIds = currentDatasource.checkIntegrity(currentDatasourceState.state); + const missingIds = currentDatasource.checkIntegrity(currentDatasourceState.state, indexPatterns); if (!missingIds.length) { return []; } @@ -179,9 +353,14 @@ export function getMissingIndexPattern( const validateRequiredIndexPatterns = ( currentDatasource: Datasource, - currentDatasourceState: { state: unknown } | null + currentDatasourceState: { state: unknown } | null, + indexPatterns: IndexPatternMap ): ErrorMessage[] | undefined => { - const missingIds = getMissingIndexPattern(currentDatasource, currentDatasourceState); + const missingIds = getMissingIndexPattern( + currentDatasource, + currentDatasourceState, + indexPatterns + ); if (!missingIds.length) { return; @@ -195,15 +374,15 @@ export const validateDatasourceAndVisualization = ( currentDatasourceState: unknown | null, currentVisualization: Visualization | null, currentVisualizationState: unknown | undefined, - frameAPI: Pick + { datasourceLayers, dataViews }: Pick ): ErrorMessage[] | undefined => { try { const datasourceValidationErrors = currentDatasourceState - ? currentDataSource?.getErrorMessages(currentDatasourceState) + ? currentDataSource?.getErrorMessages(currentDatasourceState, dataViews.indexPatterns) : undefined; const visualizationValidationErrors = currentVisualizationState - ? currentVisualization?.getErrorMessages(currentVisualizationState, frameAPI.datasourceLayers) + ? currentVisualization?.getErrorMessages(currentVisualizationState, datasourceLayers) : undefined; if (datasourceValidationErrors?.length || visualizationValidationErrors?.length) { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts index a265f534627b67..5cc62012a50949 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.test.ts @@ -7,14 +7,19 @@ import type { PaletteOutput } from '@kbn/coloring'; import { getSuggestions, getTopSuggestionForField } from './suggestion_helpers'; -import { createMockVisualization, createMockDatasource, DatasourceMock } from '../../mocks'; +import { + createMockVisualization, + createMockDatasource, + DatasourceMock, + createMockFramePublicAPI, +} from '../../mocks'; import { TableSuggestion, DatasourceSuggestion, Visualization, VisualizeEditorContext, } from '../../types'; -import { DatasourceStates } from '../../state_management'; +import { DatasourceStates, DataViewsState } from '../../state_management'; const generateSuggestion = (state = {}, layerId: string = 'first'): DatasourceSuggestion => ({ state, @@ -29,6 +34,7 @@ const generateSuggestion = (state = {}, layerId: string = 'first'): DatasourceSu let datasourceMap: Record; let datasourceStates: DatasourceStates; +let dataViews: DataViewsState; beforeEach(() => { datasourceMap = { @@ -41,6 +47,8 @@ beforeEach(() => { state: {}, }, }; + + dataViews = createMockFramePublicAPI().dataViews; }); describe('suggestion helpers', () => { @@ -69,6 +77,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(suggestions).toHaveLength(1); expect(suggestions[0].visualizationState).toBe(suggestedState); @@ -116,6 +125,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(suggestions).toHaveLength(3); }); @@ -133,11 +143,13 @@ describe('suggestion helpers', () => { datasourceMap, datasourceStates, field: droppedField, + dataViews, }); expect(datasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith( datasourceStates.mock.state, droppedField, - expect.any(Function) + expect.any(Function), + dataViews.indexPatterns ); }); @@ -168,16 +180,19 @@ describe('suggestion helpers', () => { datasourceMap: multiDatasourceMap, datasourceStates: multiDatasourceStates, field: droppedField, + dataViews, }); expect(multiDatasourceMap.mock.getDatasourceSuggestionsForField).toHaveBeenCalledWith( multiDatasourceStates.mock.state, droppedField, - expect.any(Function) + expect.any(Function), + dataViews.indexPatterns ); expect(multiDatasourceMap.mock2.getDatasourceSuggestionsForField).toHaveBeenCalledWith( multiDatasourceStates.mock2.state, droppedField, - expect.any(Function) + expect.any(Function), + dataViews.indexPatterns ); expect(multiDatasourceMap.mock3.getDatasourceSuggestionsForField).not.toHaveBeenCalled(); }); @@ -201,11 +216,13 @@ describe('suggestion helpers', () => { indexPatternId: '1', fieldName: 'test', }, + dataViews, }); expect(datasourceMap.mock.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith( datasourceStates.mock.state, '1', - 'test' + 'test', + dataViews.indexPatterns ); }); @@ -240,16 +257,19 @@ describe('suggestion helpers', () => { datasourceMap: multiDatasourceMap, datasourceStates: multiDatasourceStates, visualizeTriggerFieldContext: visualizeTriggerField, + dataViews, }); expect(multiDatasourceMap.mock.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith( multiDatasourceStates.mock.state, '1', - 'test' + 'test', + dataViews.indexPatterns ); expect(multiDatasourceMap.mock2.getDatasourceSuggestionsForVisualizeField).toHaveBeenCalledWith( multiDatasourceStates.mock2.state, '1', - 'test' + 'test', + dataViews.indexPatterns ); expect( multiDatasourceMap.mock3.getDatasourceSuggestionsForVisualizeField @@ -320,10 +340,12 @@ describe('suggestion helpers', () => { datasourceMap, datasourceStates, visualizeTriggerFieldContext: triggerContext, + dataViews, }); expect(datasourceMap.mock.getDatasourceSuggestionsForVisualizeCharts).toHaveBeenCalledWith( datasourceStates.mock.state, - triggerContext.layers + triggerContext.layers, + dataViews.indexPatterns ); }); @@ -402,15 +424,21 @@ describe('suggestion helpers', () => { datasourceMap: multiDatasourceMap, datasourceStates: multiDatasourceStates, visualizeTriggerFieldContext: triggerContext, + dataViews, }); expect(multiDatasourceMap.mock.getDatasourceSuggestionsForVisualizeCharts).toHaveBeenCalledWith( datasourceStates.mock.state, - triggerContext.layers + triggerContext.layers, + dataViews.indexPatterns ); expect( multiDatasourceMap.mock2.getDatasourceSuggestionsForVisualizeCharts - ).toHaveBeenCalledWith(multiDatasourceStates.mock2.state, triggerContext.layers); + ).toHaveBeenCalledWith( + multiDatasourceStates.mock2.state, + triggerContext.layers, + dataViews.indexPatterns + ); expect( multiDatasourceMap.mock3.getDatasourceSuggestionsForVisualizeCharts ).not.toHaveBeenCalled(); @@ -458,6 +486,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(suggestions[0].score).toBe(0.8); expect(suggestions[1].score).toBe(0.6); @@ -493,6 +522,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(mockVisualization1.getSuggestions.mock.calls[0][0].table).toEqual(table1); expect(mockVisualization1.getSuggestions.mock.calls[1][0].table).toEqual(table2); @@ -553,6 +583,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(suggestions[0].datasourceState).toBe(tableState1); expect(suggestions[0].datasourceId).toBe('mock'); @@ -582,6 +613,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(mockVisualization1.getSuggestions).toHaveBeenCalledWith( expect.objectContaining({ @@ -614,6 +646,7 @@ describe('suggestion helpers', () => { datasourceMap, datasourceStates, mainPalette, + dataViews, }); expect(mockVisualization1.getSuggestions).toHaveBeenCalledWith( expect.objectContaining({ @@ -647,6 +680,7 @@ describe('suggestion helpers', () => { visualizationState: {}, datasourceMap, datasourceStates, + dataViews, }); expect(mockVisualization1.getMainPalette).toHaveBeenCalledWith({}); expect(mockVisualization2.getSuggestions).toHaveBeenCalledWith( @@ -716,6 +750,7 @@ describe('suggestion helpers', () => { { testVis: mockVisualization1 }, datasourceMap.mock, { id: 'myfield', humanData: { label: 'myfieldLabel' } }, + dataViews, ]; }); @@ -730,7 +765,8 @@ describe('suggestion helpers', () => { label: 'myfieldLabel', }, }, - expect.any(Function) + expect.any(Function), + dataViews.indexPatterns ); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts index 620de25aa52946..5daa15fd90eb44 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_helpers.ts @@ -29,6 +29,7 @@ import { DatasourceStates, VisualizationState, applyChanges, + DataViewsState, } from '../../state_management'; /** @@ -49,6 +50,7 @@ export function getSuggestions({ field, visualizeTriggerFieldContext, activeData, + dataViews, mainPalette, }: { datasourceMap: DatasourceMap; @@ -60,6 +62,7 @@ export function getSuggestions({ field?: unknown; visualizeTriggerFieldContext?: VisualizeFieldContext | VisualizeEditorContext; activeData?: Record; + dataViews: DataViewsState; mainPalette?: PaletteOutput; }): Suggestion[] { const datasources = Object.entries(datasourceMap).filter( @@ -86,7 +89,6 @@ export function getSuggestions({ const datasourceTableSuggestions = datasources.flatMap(([datasourceId, datasource]) => { const datasourceState = datasourceStates[datasourceId].state; let dataSourceSuggestions; - try { // context is used to pass the state from location to datasource if (visualizeTriggerFieldContext) { @@ -94,25 +96,29 @@ export function getSuggestions({ if ('isVisualizeAction' in visualizeTriggerFieldContext) { dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeCharts( datasourceState, - visualizeTriggerFieldContext.layers + visualizeTriggerFieldContext.layers, + dataViews.indexPatterns ); } else { // used for navigating from Discover to Lens dataSourceSuggestions = datasource.getDatasourceSuggestionsForVisualizeField( datasourceState, visualizeTriggerFieldContext.indexPatternId, - visualizeTriggerFieldContext.fieldName + visualizeTriggerFieldContext.fieldName, + dataViews.indexPatterns ); } } else if (field) { dataSourceSuggestions = datasource.getDatasourceSuggestionsForField( datasourceState, field, - (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]) // a field dragged to workspace should added to data layer + (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]), // a field dragged to workspace should added to data layer + dataViews.indexPatterns ); } else { dataSourceSuggestions = datasource.getDatasourceSuggestionsFromCurrentState( datasourceState, + dataViews.indexPatterns, (layerId) => isLayerSupportedByVisualization(layerId, [layerTypes.DATA]), activeData ); @@ -169,12 +175,14 @@ export function getVisualizeFieldSuggestions({ datasourceStates, visualizationMap, visualizeTriggerFieldContext, + dataViews, }: { datasourceMap: DatasourceMap; datasourceStates: DatasourceStates; visualizationMap: VisualizationMap; subVisualizationId?: string; visualizeTriggerFieldContext?: VisualizeFieldContext | VisualizeEditorContext; + dataViews: DataViewsState; }): Suggestion | undefined { const activeVisualization = visualizationMap?.[Object.keys(visualizationMap)[0]] || null; const suggestions = getSuggestions({ @@ -184,6 +192,7 @@ export function getVisualizeFieldSuggestions({ activeVisualization, visualizationState: undefined, visualizeTriggerFieldContext, + dataViews, }); if (visualizeTriggerFieldContext && 'isVisualizeAction' in visualizeTriggerFieldContext) { @@ -278,7 +287,8 @@ export function getTopSuggestionForField( datasourceStates: DatasourceStates, visualizationMap: Record>, datasource: Datasource, - field: DragDropIdentifier + field: DragDropIdentifier, + dataViews: DataViewsState ) { const hasData = Object.values(datasourceLayers).some( (datasourceLayer) => datasourceLayer && datasourceLayer.getTableSpec().length > 0 @@ -300,6 +310,7 @@ export function getTopSuggestionForField( visualizationState: visualization.state, field, mainPalette, + dataViews, }); return ( suggestions.find((s) => s.visualizationId === visualization.activeId) || diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 9eafb0476afd3d..aa29a609244523 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -210,7 +210,8 @@ export function SuggestionPanel({ const missingIndexPatterns = getMissingIndexPattern( activeDatasourceId ? datasourceMap[activeDatasourceId] : null, - activeDatasourceId ? datasourceStates[activeDatasourceId] : null + activeDatasourceId ? datasourceStates[activeDatasourceId] : null, + frame.dataViews.indexPatterns ); const { suggestions, currentStateExpression, currentStateError } = useMemo(() => { const newSuggestions = missingIndexPatterns.length @@ -224,6 +225,7 @@ export function SuggestionPanel({ : undefined, visualizationState: currentVisualization.state, activeData, + dataViews: frame.dataViews, }) .filter( ({ @@ -241,6 +243,7 @@ export function SuggestionPanel({ visualizationMap[visualizationId], suggestionVisualizationState, { + dataViews: frame.dataViews, datasourceLayers: getDatasourceLayers( suggestionDatasourceId ? { @@ -250,7 +253,8 @@ export function SuggestionPanel({ }, } : {}, - datasourceMap + datasourceMap, + frame.dataViews.indexPatterns ), } ) == null @@ -493,7 +497,6 @@ function getPreviewExpression( const suggestionFrameApi: Pick = { datasourceLayers: { ...frame.datasourceLayers }, }; - try { // use current frame api and patch apis for changed datasource layers if ( @@ -513,6 +516,7 @@ function getPreviewExpression( updatedLayerApis[layerId] = datasource.getPublicAPI({ layerId, state: datasourceState, + indexPatterns: frame.dataViews.indexPatterns, }); } }); @@ -520,7 +524,8 @@ function getPreviewExpression( const datasourceExpressionsByLayers = getDatasourceExpressionsByLayers( datasources, - datasourceStates + datasourceStates, + frame.dataViews.indexPatterns ); return visualization.toPreviewExpression( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx index 7e1e489298250b..2e81f9443ff156 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx @@ -518,6 +518,7 @@ function getTopSuggestion( subVisualizationId, activeData: props.framePublicAPI.activeData, mainPalette, + dataViews: props.framePublicAPI.dataViews, }); const suggestions = unfilteredSuggestions.filter((suggestion) => { // don't use extended versions of current data table on switching between visualizations diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index e6abf77b522068..9d23dd28b37075 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -189,6 +189,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ datasourceLayers, }; + const { dataViews } = framePublicAPI; const onRender$ = useCallback(() => { if (renderDeps.current) { const datasourceEvents = Object.values(renderDeps.current.datasourceMap).reduce( @@ -242,7 +243,8 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const missingIndexPatterns = getMissingIndexPattern( activeDatasourceId ? datasourceMap[activeDatasourceId] : null, - activeDatasourceId ? datasourceStates[activeDatasourceId] : null + activeDatasourceId ? datasourceStates[activeDatasourceId] : null, + dataViews.indexPatterns ); const missingRefsErrors = missingIndexPatterns.length @@ -289,6 +291,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ datasourceMap, datasourceStates, datasourceLayers, + indexPatterns: dataViews.indexPatterns, }); if (ast) { @@ -330,6 +333,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ missingRefsErrors.length, unknownVisError, visualization.activeId, + dataViews.indexPatterns, ]); useEffect(() => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index dea3f7c43a4a82..8c7e2378bd354f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -6,14 +6,23 @@ */ import React from 'react'; -import { CoreStart } from '@kbn/core/public'; +import { CoreStart, IUiSettingsClient } from '@kbn/core/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { ExpressionsSetup, ExpressionsStart } from '@kbn/expressions-plugin/public'; import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { + DataPublicPluginSetup, + DataPublicPluginStart, + DataViewsContract, +} from '@kbn/data-plugin/public'; +import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import { DashboardStart } from '@kbn/dashboard-plugin/public'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; +import { + DataViewsPublicPluginSetup, + DataViewsPublicPluginStart, +} from '@kbn/data-views-plugin/public'; import { Document } from '../persistence/saved_object_store'; import { Datasource, @@ -29,6 +38,7 @@ export interface EditorFrameSetupPlugins { expressions: ExpressionsSetup; charts: ChartsPluginSetup; usageCollection?: UsageCollectionSetup; + dataViews: DataViewsPublicPluginSetup; } export interface EditorFrameStartPlugins { @@ -38,6 +48,13 @@ export interface EditorFrameStartPlugins { dashboard?: DashboardStart; expressions: ExpressionsStart; charts: ChartsPluginSetup; + dataViews: DataViewsPublicPluginStart; +} + +export interface EditorFramePlugins { + dataViews: DataViewsContract; + uiSettings: IUiSettingsClient; + storage: IStorageWrapper; } async function collectAsyncDefinitions( @@ -67,7 +84,7 @@ export class EditorFrameService { * This is an asynchronous process. * @param doc parsed Lens saved object */ - public documentToExpression = async (doc: Document) => { + public documentToExpression = async (doc: Document, services: EditorFramePlugins) => { const [resolvedDatasources, resolvedVisualizations] = await Promise.all([ this.loadDatasources(), this.loadVisualizations(), @@ -75,7 +92,7 @@ export class EditorFrameService { const { persistedStateToExpression } = await import('../async_services'); - return await persistedStateToExpression(resolvedDatasources, resolvedVisualizations, doc); + return persistedStateToExpression(resolvedDatasources, resolvedVisualizations, doc, services); }; public setup(): EditorFrameSetup { @@ -99,7 +116,7 @@ export class EditorFrameService { const { EditorFrame } = await import('../async_services'); return { - EditorFrameContainer: ({ showNoDataPopover, lensInspector }) => { + EditorFrameContainer: ({ showNoDataPopover, lensInspector, indexPatternService }) => { return (
    ; diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx index b1651ad36e0826..8dcd91dca41842 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx @@ -144,7 +144,7 @@ describe('embeddable', () => { data: dataMock, expressionRenderer, basePath, - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -195,7 +195,7 @@ describe('embeddable', () => { data: dataMock, expressionRenderer, basePath, - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -254,7 +254,7 @@ describe('embeddable', () => { uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, expressionRenderer, basePath, - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, inspector: inspectorPluginMock.createStartContract(), capabilities: { canSaveDashboards: true, @@ -307,7 +307,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -369,7 +369,7 @@ describe('embeddable', () => { inspector: inspectorPluginMock.createStartContract(), expressionRenderer, basePath, - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, spaces: spacesPluginStart, capabilities: { canSaveDashboards: true, @@ -420,7 +420,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: { + dataViews: { get: (id: string) => Promise.resolve({ id, isTimeBased: jest.fn(() => true) }), } as unknown as DataViewsContract, capabilities: { @@ -471,7 +471,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: { + dataViews: { get: (id: string) => Promise.resolve({ id, isTimeBased: () => false }), } as unknown as DataViewsContract, capabilities: { @@ -520,7 +520,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -573,7 +573,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -630,7 +630,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -685,7 +685,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -747,7 +747,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -810,7 +810,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -876,7 +876,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: { get: jest.fn() } as unknown as DataViewsContract, + dataViews: { get: jest.fn() } as unknown as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -927,7 +927,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -980,7 +980,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1030,7 +1030,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1095,7 +1095,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1179,7 +1179,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1238,7 +1238,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1294,7 +1294,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, @@ -1371,7 +1371,7 @@ describe('embeddable', () => { expressionRenderer, basePath, inspector: inspectorPluginMock.createStartContract(), - indexPatternService: {} as DataViewsContract, + dataViews: {} as DataViewsContract, capabilities: { canSaveDashboards: true, canSaveVisualizations: true, diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 7376c9328afe8f..6aa2c19de6705b 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -68,6 +68,7 @@ import { Visualization, DatasourceMap, Datasource, + IndexPatternMap, } from '../types'; import { getEditPath, DOC_TYPE } from '../../common'; @@ -77,6 +78,7 @@ import { getLensInspectorService, LensInspector } from '../lens_inspector_servic import { SharingSavedObjectProps, VisualizationDisplayOptions } from '../types'; import { getActiveDatasourceIdFromDoc, getIndexPatternsObjects, inferTimeField } from '../utils'; import { getLayerMetaInfo, combineQueryAndFilters } from '../app_plugin/show_underlying_data'; +import { convertDataViewIntoLensIndexPattern } from '../indexpattern_service/loader'; export type LensSavedObjectAttributes = Omit; @@ -123,7 +125,7 @@ export interface LensEmbeddableDeps { injectFilterReferences: FilterManager['inject']; visualizationMap: VisualizationMap; datasourceMap: DatasourceMap; - indexPatternService: DataViewsContract; + dataViews: DataViewsContract; expressionRenderer: ReactExpressionRendererType; timefilter: TimefilterContract; basePath: IBasePath; @@ -171,6 +173,7 @@ function getViewUnderlyingDataArgs({ filters, timeRange, esQueryConfig, + indexPatternsCache, }: { activeDatasource: Datasource; activeDatasourceState: unknown; @@ -181,11 +184,13 @@ function getViewUnderlyingDataArgs({ filters: Filter[]; timeRange: TimeRange; esQueryConfig: EsQueryConfig; + indexPatternsCache: IndexPatternMap; }) { const { error, meta } = getLayerMetaInfo( activeDatasource, activeDatasourceState, activeData, + indexPatternsCache, timeRange, capabilities ); @@ -754,7 +759,7 @@ export class Embeddable private async loadViewUnderlyingDataArgs(): Promise { const mergedSearchContext = this.getMergedSearchContext(); - if (!this.activeDataInfo.activeData || !mergedSearchContext.timeRange) { + if (!this.activeDataInfo.activeData || !mergedSearchContext.timeRange || !this.savedVis) { return false; } @@ -766,12 +771,22 @@ export class Embeddable this.activeDataInfo.activeDatasource = this.deps.datasourceMap[activeDatasourceId]; const docDatasourceState = this.savedVis?.state.datasourceStates[activeDatasourceId]; + const indexPatternsCache = this.indexPatterns.reduce( + (acc, indexPattern) => ({ + [indexPattern.id!]: convertDataViewIntoLensIndexPattern(indexPattern), + ...acc, + }), + {} + ); + if (!this.activeDataInfo.activeDatasourceState) { - this.activeDataInfo.activeDatasourceState = - await this.activeDataInfo.activeDatasource.initialize( - docDatasourceState, - this.savedVis?.references - ); + this.activeDataInfo.activeDatasourceState = this.activeDataInfo.activeDatasource.initialize( + docDatasourceState, + this.savedVis?.references, + undefined, + undefined, + indexPatternsCache + ); } const viewUnderlyingDataArgs = getViewUnderlyingDataArgs({ @@ -784,6 +799,7 @@ export class Embeddable filters: mergedSearchContext.filters || [], timeRange: mergedSearchContext.timeRange, esQueryConfig: getEsQueryConfig(this.deps.uiSettings), + indexPatternsCache, }); const loaded = typeof viewUnderlyingDataArgs !== 'undefined'; @@ -813,7 +829,7 @@ export class Embeddable const { indexPatterns } = await getIndexPatternsObjects( this.savedVis?.references.map(({ id }) => id) || [], - this.deps.indexPatternService + this.deps.dataViews ); this.indexPatterns = uniqBy(indexPatterns, 'id'); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts index 559ba9d780ff0f..d96c2aee26c03d 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts @@ -42,7 +42,7 @@ export interface LensEmbeddableStartServices { attributeService: LensAttributeService; capabilities: RecursiveReadonly; expressionRenderer: ReactExpressionRendererType; - indexPatternService: DataViewsContract; + dataViews: DataViewsContract; uiActions?: UiActionsStart; usageCollection?: UsageCollectionSetup; documentToExpression: ( @@ -107,7 +107,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { uiActions, coreHttp, attributeService, - indexPatternService, + dataViews, capabilities, usageCollection, theme, @@ -122,7 +122,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { { attributeService, data, - indexPatternService, + dataViews, timefilter, inspector, expressionRenderer, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts index 072087e0de65c0..1273d596576c40 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/__mocks__/loader.ts @@ -10,17 +10,9 @@ import { IndexPatternPrivateState } from '../types'; export function loadInitialState() { const indexPattern = createMockedIndexPattern(); - const restricted = createMockedRestrictedIndexPattern(); const result: IndexPatternPrivateState = { currentIndexPatternId: indexPattern.id, - indexPatternRefs: [], - existingFields: {}, - indexPatterns: { - [indexPattern.id]: indexPattern, - [restricted.id]: restricted, - }, layers: {}, - isFirstExistenceFetch: false, }; return result; } @@ -30,3 +22,17 @@ const originalLoader = jest.requireActual('../loader'); export const extractReferences = originalLoader.extractReferences; export const injectReferences = originalLoader.injectReferences; + +export function loadInitialDataViews() { + const indexPattern = createMockedIndexPattern(); + const restricted = createMockedRestrictedIndexPattern(); + return { + indexPatternRefs: [], + existingFields: {}, + indexPatterns: { + [indexPattern.id]: indexPattern, + [restricted.id]: restricted, + }, + isFirstExistenceFetch: false, + }; +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx index 256f452c2ab2ab..75ebbfdeb27a41 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/change_indexpattern.tsx @@ -10,7 +10,7 @@ import React, { useState } from 'react'; import { EuiPopover, EuiPopoverTitle, EuiSelectableProps } from '@elastic/eui'; import { ToolbarButton, ToolbarButtonProps } from '@kbn/kibana-react-plugin/public'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; -import { IndexPatternRef } from './types'; +import type { IndexPatternRef } from '../types'; export type ChangeIndexPatternTriggerProps = ToolbarButtonProps & { label: string; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 2bd1601eefc85e..7a3986ec3f5ba8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -10,7 +10,7 @@ import ReactDOM from 'react-dom'; import { createMockedDragDropContext } from './mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import { InnerIndexPatternDataPanel, IndexPatternDataPanel, MemoizedDataPanel } from './datapanel'; +import { InnerIndexPatternDataPanel, IndexPatternDataPanel, Props } from './datapanel'; import { FieldList } from './field_list'; import { FieldItem } from './field_item'; import { NoFieldsCallout } from './no_fields_callout'; @@ -27,6 +27,11 @@ import { getFieldByNameFactory } from './pure_helpers'; import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { TermsIndexPatternColumn } from './operations'; import { DOCUMENT_FIELD_NAME } from '../../common'; +import { createIndexPatternServiceMock } from '../mocks/data_views_service_mock'; +import { createMockFramePublicAPI } from '../mocks'; +import { DataViewsState } from '../state_management'; +import { ExistingFieldsMap, FramePublicAPI, IndexPattern } from '../types'; +import { IndexPatternServiceProps } from '../indexpattern_service/service'; const fieldsOne = [ { @@ -152,9 +157,19 @@ const fieldsThree = [ documentField, ]; +function getExistingFields(indexPatterns: Record) { + const existingFields: ExistingFieldsMap = {}; + for (const { title, fields } of Object.values(indexPatterns)) { + const fieldsMap: Record = {}; + for (const { displayName, name } of fields) { + fieldsMap[displayName ?? name] = true; + } + existingFields[title] = fieldsMap; + } + return existingFields; +} + const initialState: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', layers: { first: { @@ -212,7 +227,11 @@ const initialState: IndexPatternPrivateState = { }, }, }, - indexPatterns: { +}; + +function getFrameAPIMock({ indexPatterns, existingFields, ...rest }: Partial = {}) { + const frameAPI = createMockFramePublicAPI(); + const defaultIndexPatterns = { '1': { id: '1', title: 'idx1', @@ -237,9 +256,18 @@ const initialState: IndexPatternPrivateState = { fields: fieldsThree, getFieldByName: getFieldByNameFactory(fieldsThree), }, - }, - isFirstExistenceFetch: false, -}; + }; + return { + ...frameAPI, + dataViews: { + ...frameAPI.dataViews, + indexPatterns: indexPatterns ?? defaultIndexPatterns, + existingFields: existingFields ?? getExistingFields(indexPatterns ?? defaultIndexPatterns), + isFirstExistenceFetch: false, + ...rest, + }, + }; +} const dslQuery = { bool: { must: [], filter: [], should: [], must_not: [] } }; @@ -255,17 +283,13 @@ describe('IndexPattern Data Panel', () => { beforeEach(() => { core = coreMock.createStart(); defaultProps = { - indexPatternRefs: [], - existingFields: {}, data: dataPluginMock.createStartContract(), dataViews: dataViewPluginMocks.createStartContract(), fieldFormats: fieldFormatsServiceMock.createStartContract(), indexPatternFieldEditor: indexPatternFieldEditorPluginMock.createStartContract(), - onUpdateIndexPattern: jest.fn(), + onIndexPatternRefresh: jest.fn(), dragDropContext: createMockedDragDropContext(), currentIndexPatternId: '1', - indexPatterns: initialState.indexPatterns, - onChangeIndexPattern: jest.fn(), core, dateRange: { fromDate: 'now-7d', @@ -278,34 +302,11 @@ describe('IndexPattern Data Panel', () => { dropOntoWorkspace: jest.fn(), hasSuggestionForField: jest.fn(() => false), uiActions: uiActionsPluginMock.createStartContract(), + indexPatternService: createIndexPatternServiceMock(), + frame: getFrameAPIMock(), }; }); - it('should call change index pattern callback', async () => { - const setStateSpy = jest.fn(); - const state = { - ...initialState, - layers: { first: { indexPatternId: '1', columnOrder: [], columns: {} } }, - }; - const changeIndexPattern = jest.fn(); - const wrapper = shallowWithIntl( - - ); - - wrapper.find(MemoizedDataPanel).prop('onChangeIndexPattern')!('2'); - - expect(changeIndexPattern).toHaveBeenCalledWith('2', state, setStateSpy); - }); - it('should render a warning if there are no index patterns', () => { const wrapper = shallowWithIntl( { state={{ ...initialState, currentIndexPatternId: '', - indexPatterns: {}, }} setState={jest.fn()} dragDropContext={{ ...createMockedDragDropContext(), dragging: { id: '1', humanData: { label: 'Label' } }, }} - changeIndexPattern={jest.fn()} + frame={createMockFramePublicAPI()} /> ); expect(wrapper.find('[data-test-subj="indexPattern-no-indexpatterns"]')).toHaveLength(1); }); describe('loading existence data', () => { - function testProps() { - const setState = jest.fn(); + function testProps(updateIndexPatterns: IndexPatternServiceProps['updateIndexPatterns']) { core.http.post.mockImplementation(async (path) => { const parts = (path as unknown as string).split('/'); const indexPatternTitle = parts[parts.length - 1]; @@ -341,36 +340,40 @@ describe('IndexPattern Data Panel', () => { }); return { ...defaultProps, - changeIndexPattern: jest.fn(), - setState, + indexPatternService: createIndexPatternServiceMock({ updateIndexPatterns, core }), + setState: jest.fn(), dragDropContext: { ...createMockedDragDropContext(), dragging: { id: '1', humanData: { label: 'Label' } }, }, dateRange: { fromDate: '2019-01-01', toDate: '2020-01-01' }, - state: { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - currentIndexPatternId: 'a', - indexPatterns: { - a: { - id: 'a', - title: 'aaa', - timeFieldName: 'atime', - fields: [], - getFieldByName: getFieldByNameFactory([]), - hasRestrictions: false, - }, - b: { - id: 'b', - title: 'bbb', - timeFieldName: 'btime', - fields: [], - getFieldByName: getFieldByNameFactory([]), - hasRestrictions: false, + frame: { + dataViews: { + indexPatternRefs: [], + existingFields: {}, + isFirstExistenceFetch: false, + indexPatterns: { + a: { + id: 'a', + title: 'aaa', + timeFieldName: 'atime', + fields: [], + getFieldByName: getFieldByNameFactory([]), + hasRestrictions: false, + }, + b: { + id: 'b', + title: 'bbb', + timeFieldName: 'btime', + fields: [], + getFieldByName: getFieldByNameFactory([]), + hasRestrictions: false, + }, }, }, + } as unknown as FramePublicAPI, + state: { + currentIndexPatternId: 'a', layers: { 1: { indexPatternId: 'a', @@ -383,9 +386,9 @@ describe('IndexPattern Data Panel', () => { } async function testExistenceLoading( - stateChanges?: unknown, - propChanges?: unknown, - props = testProps() + props: Props, + stateChanges?: Partial, + propChanges?: Partial ) { const inst = mountWithIntl(); @@ -395,7 +398,7 @@ describe('IndexPattern Data Panel', () => { if (stateChanges || propChanges) { await act(async () => { - (inst.setProps as unknown as (props: unknown) => {})({ + inst.setProps({ ...props, ...((propChanges as object) || {}), state: { @@ -406,63 +409,70 @@ describe('IndexPattern Data Panel', () => { inst.update(); }); } - - return props.setState; } it('loads existence data', async () => { - const setState = await testExistenceLoading(); - - expect(setState).toHaveBeenCalledTimes(1); - - const nextState = setState.mock.calls[0][0]({ - existingFields: {}, - }); - - expect(nextState.existingFields).toEqual({ - a_testtitle: { - a_field_1: true, - a_field_2: true, + const updateIndexPatterns = jest.fn(); + await testExistenceLoading(testProps(updateIndexPatterns)); + + expect(updateIndexPatterns).toHaveBeenCalledWith( + { + existingFields: { + a_testtitle: { + a_field_1: true, + a_field_2: true, + }, + }, + isFirstExistenceFetch: false, }, - }); + { applyImmediately: true } + ); }); it('loads existence data for current index pattern id', async () => { - const setState = await testExistenceLoading({ currentIndexPatternId: 'b' }); - - expect(setState).toHaveBeenCalledTimes(2); - - const nextState = setState.mock.calls[1][0]({ - existingFields: {}, + const updateIndexPatterns = jest.fn(); + await testExistenceLoading(testProps(updateIndexPatterns), { + currentIndexPatternId: 'b', }); - expect(nextState.existingFields).toEqual({ - a_testtitle: { - a_field_1: true, - a_field_2: true, - }, - b_testtitle: { - b_field_1: true, - b_field_2: true, + expect(updateIndexPatterns).toHaveBeenCalledWith( + { + existingFields: { + a_testtitle: { + a_field_1: true, + a_field_2: true, + }, + b_testtitle: { + b_field_1: true, + b_field_2: true, + }, + }, + isFirstExistenceFetch: false, }, - }); + { applyImmediately: true } + ); }); it('does not load existence data if date and index pattern ids are unchanged', async () => { - const setState = await testExistenceLoading({ - currentIndexPatternId: 'a', - dateRange: { fromDate: '2019-01-01', toDate: '2020-01-01' }, - }); + const updateIndexPatterns = jest.fn(); + await testExistenceLoading( + testProps(updateIndexPatterns), + { + currentIndexPatternId: 'a', + }, + { dateRange: { fromDate: '2019-01-01', toDate: '2020-01-01' } } + ); - expect(setState).toHaveBeenCalledTimes(1); + expect(updateIndexPatterns).toHaveBeenCalledTimes(1); }); it('loads existence data if date range changes', async () => { - const setState = await testExistenceLoading(undefined, { + const updateIndexPatterns = jest.fn(); + await testExistenceLoading(testProps(updateIndexPatterns), undefined, { dateRange: { fromDate: '2019-01-01', toDate: '2020-01-02' }, }); - expect(setState).toHaveBeenCalledTimes(2); + expect(updateIndexPatterns).toHaveBeenCalledTimes(2); expect(core.http.post).toHaveBeenCalledTimes(2); expect(core.http.post).toHaveBeenCalledWith('/api/lens/existing_fields/a', { @@ -483,28 +493,33 @@ describe('IndexPattern Data Panel', () => { }), }); - const nextState = setState.mock.calls[1][0]({ - existingFields: {}, - }); - - expect(nextState.existingFields).toEqual({ - a_testtitle: { - a_field_1: true, - a_field_2: true, + expect(updateIndexPatterns).toHaveBeenCalledWith( + { + existingFields: { + a_testtitle: { + a_field_1: true, + a_field_2: true, + }, + }, + isFirstExistenceFetch: false, }, - }); + { applyImmediately: true } + ); }); it('loads existence data if layer index pattern changes', async () => { - const setState = await testExistenceLoading({ + const updateIndexPatterns = jest.fn(); + await testExistenceLoading(testProps(updateIndexPatterns), { layers: { 1: { indexPatternId: 'b', + columnOrder: [], + columns: {}, }, }, }); - expect(setState).toHaveBeenCalledTimes(2); + expect(updateIndexPatterns).toHaveBeenCalledTimes(2); expect(core.http.post).toHaveBeenCalledWith('/api/lens/existing_fields/a', { body: JSON.stringify({ @@ -524,25 +539,28 @@ describe('IndexPattern Data Panel', () => { }), }); - const nextState = setState.mock.calls[1][0]({ - existingFields: {}, - }); - - expect(nextState.existingFields).toEqual({ - a_testtitle: { - a_field_1: true, - a_field_2: true, - }, - b_testtitle: { - b_field_1: true, - b_field_2: true, + expect(updateIndexPatterns).toHaveBeenCalledWith( + { + existingFields: { + a_testtitle: { + a_field_1: true, + a_field_2: true, + }, + b_testtitle: { + b_field_1: true, + b_field_2: true, + }, + }, + isFirstExistenceFetch: false, }, - }); + { applyImmediately: true } + ); }); it('shows a loading indicator when loading', async () => { + const updateIndexPatterns = jest.fn(); const load = async () => {}; - const inst = mountWithIntl(); + const inst = mountWithIntl(); expect(inst.find(EuiProgress).length).toEqual(1); await act(load); inst.update(); @@ -550,9 +568,10 @@ describe('IndexPattern Data Panel', () => { }); it('does not perform multiple queries at once', async () => { + const updateIndexPatterns = jest.fn(); let queryCount = 0; let overlapCount = 0; - const props = testProps(); + const props = testProps(updateIndexPatterns); core.http.post.mockImplementation((path) => { if (queryCount) { @@ -599,14 +618,15 @@ describe('IndexPattern Data Panel', () => { }); it("should default to empty dsl if query can't be parsed", async () => { + const updateIndexPatterns = jest.fn(); const props = { - ...testProps(), + ...testProps(updateIndexPatterns), query: { language: 'kuery', query: '@timestamp : NOT *', }, }; - await testExistenceLoading(undefined, undefined, props); + await testExistenceLoading(props, undefined, undefined); expect((props.core.http.post as jest.Mock).mock.calls[0][1].body).toContain( JSON.stringify({ @@ -623,12 +643,14 @@ describe('IndexPattern Data Panel', () => { beforeEach(() => { props = { ...defaultProps, - existingFields: { - idx1: { - bytes: true, - memory: true, + frame: getFrameAPIMock({ + existingFields: { + idx1: { + bytes: true, + memory: true, + }, }, - }, + }), }; }); it('should list all supported fields in the pattern sorted alphabetically in groups', async () => { @@ -658,22 +680,24 @@ describe('IndexPattern Data Panel', () => { const wrapper = mountWithIntl( ); wrapper @@ -692,7 +716,10 @@ describe('IndexPattern Data Panel', () => { it('should display NoFieldsCallout when all fields are empty', async () => { const wrapper = mountWithIntl( - + ); expect(wrapper.find(NoFieldsCallout).length).toEqual(2); expect( @@ -715,18 +742,26 @@ describe('IndexPattern Data Panel', () => { }); it('should display spinner for available fields accordion if existing fields are not loaded yet', async () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); expect( wrapper.find('[data-test-subj="lnsIndexPatternAvailableFields"]').find(EuiLoadingSpinner) .length ).toEqual(1); - wrapper.setProps({ existingFields: { idx1: {} } }); + wrapper.setProps({ frame: getFrameAPIMock({ existingFields: { idx1: {} } }) }); expect(wrapper.find(NoFieldsCallout).length).toEqual(2); }); it('should not allow field details when error', () => { const wrapper = mountWithIntl( - + ); expect(wrapper.find(FieldList).prop('fieldGroups')).toEqual( @@ -738,7 +773,10 @@ describe('IndexPattern Data Panel', () => { it('should allow field details when timeout', () => { const wrapper = mountWithIntl( - + ); expect(wrapper.find(FieldList).prop('fieldGroups')).toEqual( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index d907c25cbaf148..300a96fb846c5c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -34,32 +34,34 @@ import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin import { VISUALIZE_GEO_FIELD_TRIGGER } from '@kbn/ui-actions-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; -import type { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; -import { ChildDragDropProvider, DragContextState } from '../drag_drop'; import type { + DatasourceDataPanelProps, + DataType, + FramePublicAPI, IndexPattern, - IndexPatternPrivateState, IndexPatternField, - IndexPatternRef, -} from './types'; -import { loadIndexPatterns, syncExistingFields } from './loader'; -import { fieldExists } from './pure_helpers'; +} from '../types'; +import { ChildDragDropProvider, DragContextState } from '../drag_drop'; +import type { IndexPatternPrivateState } from './types'; import { Loader } from '../loader'; import { LensFieldIcon } from '../shared_components/field_picker/lens_field_icon'; import { FieldGroups, FieldList } from './field_list'; +import { fieldContainsData, fieldExists } from '../shared_components'; +import { IndexPatternServiceAPI } from '../indexpattern_service/service'; -export type Props = Omit, 'core'> & { +export type Props = Omit< + DatasourceDataPanelProps, + 'core' | 'onChangeIndexPattern' +> & { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; fieldFormats: FieldFormatsStart; - changeIndexPattern: ( - id: string, - state: IndexPatternPrivateState, - setState: StateSetter - ) => void; charts: ChartsPluginSetup; core: CoreStart; indexPatternFieldEditor: IndexPatternFieldEditorStart; + frame: FramePublicAPI; + indexPatternService: IndexPatternServiceAPI; + onIndexPatternRefresh: () => void; }; function sortFields(fieldA: IndexPatternField, fieldB: IndexPatternField) { @@ -117,7 +119,6 @@ function buildSafeEsQuery( } export function IndexPatternDataPanel({ - setState, state, dragDropContext, core, @@ -127,32 +128,19 @@ export function IndexPatternDataPanel({ query, filters, dateRange, - changeIndexPattern, charts, indexPatternFieldEditor, showNoDataPopover, dropOntoWorkspace, hasSuggestionForField, uiActions, + indexPatternService, + frame, + onIndexPatternRefresh, }: Props) { - const { indexPatternRefs, indexPatterns, currentIndexPatternId } = state; - const onChangeIndexPattern = useCallback( - (id: string) => changeIndexPattern(id, state, setState), - [state, setState, changeIndexPattern] - ); - - const onUpdateIndexPattern = useCallback( - (indexPattern: IndexPattern) => { - setState((prevState) => ({ - ...prevState, - indexPatterns: { - ...prevState.indexPatterns, - [indexPattern.id]: indexPattern, - }, - })); - }, - [setState] - ); + const { indexPatterns, indexPatternRefs, existingFields, isFirstExistenceFetch } = + frame.dataViews; + const { currentIndexPatternId } = state; const indexPatternList = uniq( Object.values(state.layers) @@ -160,14 +148,8 @@ export function IndexPatternDataPanel({ .concat(currentIndexPatternId) ) .filter((id) => !!indexPatterns[id]) - .sort((a, b) => a.localeCompare(b)) - .map((id) => ({ - id, - title: indexPatterns[id].title, - timeFieldName: indexPatterns[id].timeFieldName, - fields: indexPatterns[id].fields, - hasRestrictions: indexPatterns[id].hasRestrictions, - })); + .sort() + .map((id) => indexPatterns[id]); const dslQuery = buildSafeEsQuery( indexPatterns[currentIndexPatternId], @@ -180,15 +162,14 @@ export function IndexPatternDataPanel({ <> - syncExistingFields({ + indexPatternService.refreshExistingFields({ dateRange, - setState, - isFirstExistenceFetch: state.isFirstExistenceFetch, currentIndexPatternTitle: indexPatterns[currentIndexPatternId]?.title || '', - showNoDataPopover, - indexPatterns: indexPatternList, - fetchJson: core.http.post, + onNoData: showNoDataPopover, dslQuery, + indexPatternList, + isFirstExistenceFetch, + existingFields, }) } loadDeps={[ @@ -197,7 +178,8 @@ export function IndexPatternDataPanel({ dateRange.fromDate, dateRange.toDate, indexPatternList.map((x) => `${x.title}:${x.timeFieldName}`).join(','), - state.indexPatterns, + // important here to rerun the fields existence on indexPattern change (i.e. add new fields in place) + frame.dataViews.indexPatterns, ]} /> @@ -229,8 +211,6 @@ export function IndexPatternDataPanel({ ) : ( )} @@ -285,42 +263,36 @@ const fieldSearchDescriptionId = htmlId(); export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ currentIndexPatternId, - indexPatternRefs, - indexPatterns, - existenceFetchFailed, - existenceFetchTimeout, query, dateRange, filters, dragDropContext, - onChangeIndexPattern, - onUpdateIndexPattern, core, data, dataViews, fieldFormats, indexPatternFieldEditor, - existingFields, charts, dropOntoWorkspace, hasSuggestionForField, uiActions, -}: Omit & { + indexPatternService, + frame, + onIndexPatternRefresh, +}: Omit< + DatasourceDataPanelProps, + 'state' | 'setState' | 'showNoDataPopover' | 'core' | 'onChangeIndexPattern' +> & { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; fieldFormats: FieldFormatsStart; core: CoreStart; currentIndexPatternId: string; - indexPatternRefs: IndexPatternRef[]; - indexPatterns: Record; dragDropContext: DragContextState; - onChangeIndexPattern: (newId: string) => void; - onUpdateIndexPattern: (indexPattern: IndexPattern) => void; - existingFields: IndexPatternPrivateState['existingFields']; charts: ChartsPluginSetup; + frame: FramePublicAPI; indexPatternFieldEditor: IndexPatternFieldEditorStart; - existenceFetchFailed?: boolean; - existenceFetchTimeout?: boolean; + onIndexPatternRefresh: () => void; }) { const [localState, setLocalState] = useState({ nameFilter: '', @@ -330,13 +302,15 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ isEmptyAccordionOpen: false, isMetaAccordionOpen: false, }); + const { existenceFetchFailed, existenceFetchTimeout, indexPatterns, existingFields } = + frame.dataViews; const currentIndexPattern = indexPatterns[currentIndexPatternId]; + const existingFieldsForIndexPattern = existingFields[currentIndexPattern?.title]; const visualizeGeoFieldTrigger = uiActions.getTrigger(VISUALIZE_GEO_FIELD_TRIGGER); const allFields = visualizeGeoFieldTrigger ? currentIndexPattern.fields : currentIndexPattern.fields.filter(({ type }) => type !== 'geo_point' && type !== 'geo_shape'); const clearLocalState = () => setLocalState((s) => ({ ...s, nameFilter: '', typeFilter: [] })); - const hasSyncedExistingFields = existingFields[currentIndexPattern.title]; const availableFieldTypes = uniq(allFields.map(({ type }) => type)).filter( (type) => type in fieldTypeNames ); @@ -349,9 +323,10 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const unfilteredFieldGroups: FieldGroups = useMemo(() => { const containsData = (field: IndexPatternField) => { const overallField = currentIndexPattern.getFieldByName(field.name); - return ( - overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) + overallField && + existingFieldsForIndexPattern && + fieldExists(existingFieldsForIndexPattern, overallField.name) ); }; @@ -463,7 +438,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ filters.length, existenceFetchTimeout, currentIndexPattern, - existingFields, + existingFieldsForIndexPattern, ]); const fieldGroups: FieldGroups = useMemo(() => { @@ -490,10 +465,9 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ }, [unfilteredFieldGroups, localState.nameFilter, localState.typeFilter]); const checkFieldExists = useCallback( - (field) => - field.type === 'document' || - fieldExists(existingFields, currentIndexPattern.title, field.name), - [existingFields, currentIndexPattern.title] + (field: IndexPatternField) => + fieldContainsData(field.name, currentIndexPattern, existingFieldsForIndexPattern), + [currentIndexPattern, existingFieldsForIndexPattern] ); const { nameFilter, typeFilter } = localState; @@ -518,15 +492,26 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ }, []); const refreshFieldList = useCallback(async () => { - const newlyMappedIndexPattern = await loadIndexPatterns({ - indexPatternsService: dataViews, - cache: {}, + const newlyMappedIndexPattern = await indexPatternService.loadIndexPatterns({ patterns: [currentIndexPattern.id], + cache: {}, + onIndexPatternRefresh, + }); + indexPatternService.updateDataViewsState({ + indexPatterns: { + ...frame.dataViews.indexPatterns, + [currentIndexPattern.id]: newlyMappedIndexPattern[currentIndexPattern.id], + }, }); - onUpdateIndexPattern(newlyMappedIndexPattern[currentIndexPattern.id]); // start a new session so all charts are refreshed data.search.session.start(); - }, [data, dataViews, currentIndexPattern, onUpdateIndexPattern]); + }, [ + indexPatternService, + currentIndexPattern.id, + onIndexPatternRefresh, + frame.dataViews.indexPatterns, + data.search.session, + ]); const editField = useMemo( () => @@ -538,9 +523,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ dataView: indexPatternInstance, }, fieldName, - onSave: async () => { - await refreshFieldList(); - }, + onSave: () => refreshFieldList(), }); } : undefined, @@ -557,9 +540,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ dataView: indexPatternInstance, }, fieldName, - onDelete: async () => { - await refreshFieldList(); - }, + onDelete: () => refreshFieldList(), }); } : undefined, @@ -709,7 +690,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ exists={checkFieldExists} fieldProps={fieldProps} fieldGroups={fieldGroups} - hasSyncedExistingFields={!!hasSyncedExistingFields} + hasSyncedExistingFields={!!existingFieldsForIndexPattern} filter={filter} currentIndexPatternId={currentIndexPatternId} existenceFetchFailed={existenceFetchFailed} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx index fbecfeed0f3214..248cc0f78756eb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx @@ -9,7 +9,7 @@ import { mount } from 'enzyme'; import React from 'react'; import { BucketNestingEditor } from './bucket_nesting_editor'; import { GenericIndexPatternColumn } from '../indexpattern'; -import { IndexPatternField } from '../types'; +import { IndexPatternField } from '../../types'; const fieldMap: Record = { a: { displayName: 'a' } as IndexPatternField, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx index 46ed51f35d9b03..31a4b91706dfac 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx @@ -8,9 +8,10 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFormRow, EuiSwitch, EuiSelect } from '@elastic/eui'; -import { IndexPatternLayer, IndexPatternField } from '../types'; +import { IndexPatternLayer } from '../types'; import { hasField } from '../pure_utils'; import { GenericIndexPatternColumn } from '../operations'; +import { IndexPatternField } from '../../types'; function nestColumn(columnOrder: string[], outer: string, inner: string) { const result = columnOrder.filter((c) => c !== inner); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 8ca86446e8be40..284caa2e35f35b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -41,7 +41,7 @@ import { mergeLayer } from '../state_helpers'; import { hasField } from '../pure_utils'; import { fieldIsInvalid } from '../utils'; import { BucketNestingEditor } from './bucket_nesting_editor'; -import type { IndexPattern, IndexPatternField, IndexPatternLayer } from '../types'; +import type { IndexPatternLayer } from '../types'; import { FormatSelector } from './format_selector'; import { ReferenceEditor } from './reference_editor'; import { TimeScaling } from './time_scaling'; @@ -67,7 +67,8 @@ import { NameInput } from '../../shared_components'; import { ParamEditorProps } from '../operations/definitions'; import { WrappingHelpPopover } from '../help_popover'; import { isColumn } from '../operations/definitions/helpers'; -import { FieldChoiceWithOperationType } from './field_select'; +import type { FieldChoiceWithOperationType } from './field_select'; +import type { IndexPattern, IndexPatternField } from '../../types'; import { documentField } from '../document_field'; export interface DimensionEditorProps extends IndexPatternDimensionEditorProps { @@ -310,7 +311,7 @@ export function DimensionEditor(props: DimensionEditorProps) { disabledStatus: definition.getDisabledStatus && definition.getDisabledStatus( - state.indexPatterns[state.currentIndexPatternId], + props.indexPatterns[state.currentIndexPatternId], state.layers[layerId], layerType ), @@ -562,7 +563,7 @@ export function DimensionEditor(props: DimensionEditorProps) { setIsCloseable, paramEditorCustomProps, ReferenceEditor, - existingFields: state.existingFields, + existingFields: props.existingFields, ...services, }; @@ -661,7 +662,7 @@ export function DimensionEditor(props: DimensionEditorProps) { }} validation={validation} currentIndexPattern={currentIndexPattern} - existingFields={state.existingFields} + existingFields={props.existingFields} selectionStyle={selectedOperationDefinition.selectionStyle} dateRange={dateRange} labelAppend={selectedOperationDefinition?.getHelpMessage?.({ @@ -687,7 +688,7 @@ export function DimensionEditor(props: DimensionEditorProps) { selectedColumn={selectedColumn as FieldBasedIndexPatternColumn} columnId={columnId} indexPattern={currentIndexPattern} - existingFields={state.existingFields} + existingFields={props.existingFields} operationSupportMatrix={operationSupportMatrix} updateLayer={(newLayer) => { if (temporaryQuickFunction) { @@ -717,7 +718,7 @@ export function DimensionEditor(props: DimensionEditorProps) { const customParamEditor = ParamEditor ? ( <> { beforeEach(() => { state = { - indexPatternRefs: [], - indexPatterns: expectedIndexPatterns, currentIndexPatternId: '1', - isFirstExistenceFetch: false, - existingFields: { - 'my-fake-index-pattern': { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, layers: { first: { indexPatternId: '1', @@ -205,6 +194,15 @@ describe('IndexPatternDimensionEditorPanel', () => { }); defaultProps = { + indexPatterns: expectedIndexPatterns, + existingFields: { + 'my-fake-index-pattern': { + timestamp: true, + bytes: true, + memory: true, + source: true, + }, + }, state, setState, dateRange: { fromDate: 'now-1d', toDate: 'now' }, @@ -339,13 +337,10 @@ describe('IndexPatternDimensionEditorPanel', () => { it('should hide fields that have no data', () => { const props = { ...defaultProps, - state: { - ...defaultProps.state, - existingFields: { - 'my-fake-index-pattern': { - timestamp: true, - source: true, - }, + existingFields: { + 'my-fake-index-pattern': { + timestamp: true, + source: true, }, }, }; @@ -1452,13 +1447,10 @@ describe('IndexPatternDimensionEditorPanel', () => { wrapper = mount( @@ -1779,34 +1771,31 @@ describe('IndexPatternDimensionEditorPanel', () => { }); it('should select operation directly if only one field is possible', () => { - const initialState = { - ...state, - indexPatterns: { - 1: { - ...state.indexPatterns['1'], - fields: state.indexPatterns['1'].fields.filter((field) => field.name !== 'memory'), - }, - }, - }; - wrapper = mount( field.name !== 'memory' + ), + }, + }} /> ); wrapper.find('button[data-test-subj="lns-indexPatternDimension-average"]').simulate('click'); expect(setState.mock.calls[0]).toEqual([expect.any(Function), { isDimensionComplete: true }]); - expect(setState.mock.calls[0][0](initialState)).toEqual({ - ...initialState, + expect(setState.mock.calls[0][0](state)).toEqual({ + ...state, layers: { first: { - ...initialState.layers.first, + ...state.layers.first, columns: { - ...initialState.layers.first.columns, + ...state.layers.first.columns, col2: expect.objectContaining({ sourceField: 'bytes', operationType: 'average', @@ -2214,35 +2203,38 @@ describe('IndexPatternDimensionEditorPanel', () => { sourceField: 'bytes', }, }), - indexPatterns: { - 1: { - id: '1', - title: 'my-fake-index-pattern', - hasRestrictions: false, - fields: [ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - getFieldByName: getFieldByNameFactory([ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ]), - }, - }, }; wrapper = mount( - + ); expect(wrapper.find('[data-test-subj="lns-indexPatternDimension-differences"]')).toHaveLength( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx index 9b50da38f1b623..e38d48034622af 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.tsx @@ -53,7 +53,7 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens ) { const layerId = props.layerId; const layer = props.state.layers[layerId]; - const currentIndexPattern = props.state.indexPatterns[layer.indexPatternId]; + const currentIndexPattern = props.indexPatterns[layer.indexPatternId]; const { columnId, uniqueLabel, invalid, invalidMessage, hideTooltip } = props; const currentColumnHasErrors = useMemo( @@ -83,8 +83,7 @@ export const IndexPatternDimensionEditorComponent = function IndexPatternDimensi props: IndexPatternDimensionEditorProps ) { const layerId = props.layerId; - const currentIndexPattern = - props.state.indexPatterns[props.state.layers[layerId]?.indexPatternId]; + const currentIndexPattern = props.indexPatterns[props.state.layers[layerId]?.indexPatternId]; if (!currentIndexPattern) { return null; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts index f48e4d897a6370..2f4d8a0121aa11 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts @@ -18,19 +18,9 @@ import { import { generateId } from '../../../id_generator'; const getDefaultProps = () => ({ + indexPatterns: mockDataViews(), state: { - indexPatternRefs: [], - indexPatterns: mockDataViews(), currentIndexPatternId: 'first', - isFirstExistenceFetch: false, - existingFields: { - first: { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, layers: { first: mockedLayers.doubleColumnLayer(), second: mockedLayers.emptyLayer() }, }, target: mockedDndOperations.notFiltering, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts index 7546ff86b8b6ef..66139b01a504a1 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts @@ -5,7 +5,14 @@ * 2.0. */ -import { isOperation, DropType, DragDropOperation } from '../../../types'; +import { + isOperation, + DropType, + DragDropOperation, + IndexPattern, + IndexPatternMap, + IndexPatternField, +} from '../../../types'; import { getCurrentFieldsForOperation, getOperationDisplay, @@ -16,13 +23,7 @@ import { DragContextState } from '../../../drag_drop/providers'; import { OperationMetadata } from '../../../types'; import { getOperationTypesForField } from '../../operations'; import { GenericIndexPatternColumn } from '../../indexpattern'; -import { - IndexPatternPrivateState, - IndexPattern, - IndexPatternField, - DraggedField, - DataViewDragDropOperation, -} from '../../types'; +import { IndexPatternPrivateState, DraggedField, DataViewDragDropOperation } from '../../types'; import { getDropPropsForSameGroup, isOperationFromTheSameGroup, @@ -32,6 +33,7 @@ interface GetDropPropsArgs { state: IndexPatternPrivateState; source?: DragContextState['dragging']; target: DragDropOperation; + indexPatterns: IndexPatternMap; } type DropProps = { dropTypes: DropType[]; nextLabel?: string } | undefined; @@ -70,14 +72,14 @@ export function getField(column: GenericIndexPatternColumn | undefined, dataView } export function getDropProps(props: GetDropPropsArgs) { - const { state, source, target } = props; + const { state, source, target, indexPatterns } = props; if (!source) { return; } const targetProps: DataViewDragDropOperation = { ...target, column: state.layers[target.layerId].columns[target.columnId], - dataView: state.indexPatterns[state.layers[target.layerId].indexPatternId], + dataView: indexPatterns[state.layers[target.layerId].indexPatternId], }; if (isDraggedField(source)) { @@ -88,7 +90,7 @@ export function getDropProps(props: GetDropPropsArgs) { const sourceProps: DataViewDragDropOperation = { ...source, column: state.layers[source.layerId]?.columns[source.columnId], - dataView: state.indexPatterns[state.layers[source.layerId]?.indexPatternId], + dataView: indexPatterns[state.layers[source.layerId]?.indexPatternId], }; if (!sourceProps.column) { return; @@ -126,6 +128,7 @@ function getDropPropsForField({ state, source, target, + indexPatterns, }: GetDropPropsArgs & { source: DraggedField }): DropProps { const targetColumn = state.layers[target.layerId].columns[target.columnId]; const isTheSameIndexPattern = @@ -141,7 +144,7 @@ function getDropPropsForField({ (hasField(targetColumn) && targetColumn.sourceField !== source.field.name) || !hasField(targetColumn) ) { - const layerDataView = state.indexPatterns[state.layers[target.layerId].indexPatternId]; + const layerDataView = indexPatterns[state.layers[target.layerId].indexPatternId]; return hasField(targetColumn) && layerDataView && hasOperationSupportForMultipleFields(layerDataView, targetColumn, undefined, source.field) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts index 40121cf99f5467..19dfaf3ac7c204 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { IndexPattern, IndexPatternLayer } from '../../types'; +import { IndexPatternLayer } from '../../types'; import { documentField } from '../../document_field'; -import { OperationMetadata } from '../../../types'; +import { IndexPatternMap, OperationMetadata } from '../../../types'; import { DateHistogramIndexPatternColumn, GenericIndexPatternColumn, @@ -17,7 +17,7 @@ import { import { getFieldByNameFactory } from '../../pure_helpers'; jest.mock('../../../id_generator'); -export const mockDataViews = (): Record => { +export const mockDataViews = (): IndexPatternMap => { const fields = [ { name: 'timestamp', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts index 12acf46c583808..3ae1672d9e4640 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts @@ -69,18 +69,7 @@ describe('IndexPatternDimensionEditorPanel: onDrop', () => { beforeEach(() => { state = { - indexPatternRefs: [], - indexPatterns: mockDataViews(), currentIndexPatternId: 'first', - isFirstExistenceFetch: false, - existingFields: { - first: { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, layers: { first: mockedLayers.singleColumnLayer(), second: mockedLayers.emptyLayer(), @@ -96,6 +85,7 @@ describe('IndexPatternDimensionEditorPanel: onDrop', () => { state, setState, dimensionGroups: [], + indexPatterns: mockDataViews(), }; jest.clearAllMocks(); @@ -1506,19 +1496,9 @@ describe('IndexPatternDimensionEditorPanel: onDrop', () => { setState = jest.fn(); props = { + indexPatterns: mockDataViews(), state: { - indexPatternRefs: [], - indexPatterns: mockDataViews(), currentIndexPatternId: 'first', - isFirstExistenceFetch: false, - existingFields: { - first: { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, layers: { first: mockedLayers.singleColumnLayer(), second: mockedLayers.multipleColumnsLayer('col2', 'col3', 'col4', 'col5'), @@ -2062,6 +2042,7 @@ describe('IndexPatternDimensionEditorPanel: onDrop', () => { setState: jest.fn(), dropType: 'move_compatible', + indexPatterns: mockDataViews(), state: { layers: { first: { @@ -2114,18 +2095,7 @@ describe('IndexPatternDimensionEditorPanel: onDrop', () => { columnOrder: ['second', 'secondX0'], }, }, - indexPatternRefs: [], - indexPatterns: mockDataViews(), currentIndexPatternId: 'first', - isFirstExistenceFetch: false, - existingFields: { - first: { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, }, source: { columnId: 'firstColumn', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts index b2c24cd5bf4389..fa2d2e5710d01b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts @@ -8,6 +8,7 @@ import { DatasourceDimensionDropHandlerProps, DragDropOperation, DropType, + IndexPatternMap, isOperation, StateSetter, VisualizationDimensionGroupConfig, @@ -41,10 +42,11 @@ interface DropHandlerProps { dropType?: DropType; source: T; target: DataViewDragDropOperation; + indexPatterns: IndexPatternMap; } export function onDrop(props: DatasourceDimensionDropHandlerProps) { - const { target, source, dropType, state } = props; + const { target, source, dropType, state, indexPatterns } = props; if (isDraggedField(source) && isFieldDropType(dropType)) { return onFieldDrop( @@ -52,9 +54,10 @@ export function onDrop(props: DatasourceDimensionDropHandlerProps ['field_add', 'field_replace', 'field_combine'].includes(dropType); function onFieldDrop(props: DropHandlerProps, shouldAddField?: boolean) { - const { setState, state, source, target, dimensionGroups } = props; + const { setState, state, source, target, dimensionGroups, indexPatterns } = props; const prioritizedOperation = dimensionGroups.find( (g) => g.groupId === target.groupId )?.prioritizedOperation; const layer = state.layers[target.layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = indexPatterns[layer.indexPatternId]; const targetColumn = layer.columns[target.columnId]; const newOperation = shouldAddField ? targetColumn.operationType @@ -233,13 +237,20 @@ function onReorder({ } function onMoveIncompatible( - { setState, state, source, dimensionGroups, target }: DropHandlerProps, + { + setState, + state, + source, + dimensionGroups, + target, + indexPatterns, + }: DropHandlerProps, shouldDeleteSource?: boolean ) { const targetLayer = state.layers[target.layerId]; const targetColumn = targetLayer.columns[target.columnId] || null; const sourceLayer = state.layers[source.layerId]; - const indexPattern = state.indexPatterns[sourceLayer.indexPatternId]; + const indexPattern = indexPatterns[sourceLayer.indexPatternId]; const sourceColumn = sourceLayer.columns[source.columnId]; const sourceField = getField(sourceColumn, indexPattern); const newOperation = getNewOperation(sourceField, target.filterOperations, targetColumn); @@ -304,10 +315,11 @@ function onSwapIncompatible({ source, dimensionGroups, target, + indexPatterns, }: DropHandlerProps) { const targetLayer = state.layers[target.layerId]; const sourceLayer = state.layers[source.layerId]; - const indexPattern = state.indexPatterns[targetLayer.indexPatternId]; + const indexPattern = indexPatterns[targetLayer.indexPatternId]; const sourceColumn = sourceLayer.columns[source.columnId]; const targetColumn = targetLayer.columns[target.columnId]; @@ -453,11 +465,12 @@ function onCombine({ source, target, dimensionGroups, + indexPatterns, }: DropHandlerProps) { const targetLayer = state.layers[target.layerId]; const targetColumn = targetLayer.columns[target.columnId]; const targetField = getField(targetColumn, target.dataView); - const indexPattern = state.indexPatterns[targetLayer.indexPatternId]; + const indexPattern = indexPatterns[targetLayer.indexPatternId]; const sourceLayer = state.layers[source.layerId]; const sourceColumn = sourceLayer.columns[source.columnId]; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_input.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_input.test.tsx index 730342ae694e89..b7ab501f34d169 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_input.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/field_input.test.tsx @@ -120,24 +120,23 @@ function getDefaultOperationSupportMatrix( return getOperationSupportMatrix({ state: { layers: { layer1: layer }, - indexPatterns: { - [defaultProps.indexPattern.id]: defaultProps.indexPattern, - }, - existingFields, } as unknown as IndexPatternPrivateState, layerId: 'layer1', filterOperations: () => true, columnId, + indexPatterns: { + [defaultProps.indexPattern.id]: defaultProps.indexPattern, + }, }); } -function getExistingFields(layer: IndexPatternLayer) { +function getExistingFields() { const fields: Record = {}; for (const field of defaultProps.indexPattern.fields) { fields[field.name] = true; } return { - [layer.indexPatternId]: fields, + [defaultProps.indexPattern.title]: fields, }; } @@ -145,7 +144,7 @@ describe('FieldInput', () => { it('should render a field select box', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should render an error message when incomplete operation is on', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { (_, col: ReferenceBasedIndexPatternColumn) => { const updateLayerSpy = jest.fn(); const layer = getLayer(col); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix( layer, 'col1', @@ -235,7 +234,7 @@ describe('FieldInput', () => { (_, col: ReferenceBasedIndexPatternColumn) => { const updateLayerSpy = jest.fn(); const layer = getLayer(col); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix( layer, 'col1', @@ -270,7 +269,7 @@ describe('FieldInput', () => { it('should render an error message for invalid fields', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should render a help message when passed and no errors are found', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should prioritize errors over help messages', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should update the layer on field selection', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should not trigger when the same selected field is selected again', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { it('should prioritize incomplete fields over selected column field to display', () => { const updateLayerSpy = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( { const updateLayerSpy = jest.fn(); const onDeleteColumn = jest.fn(); const layer = getLayer(); - const existingFields = getExistingFields(layer); + const existingFields = getExistingFields(); const operationSupportMatrix = getDefaultOperationSupportMatrix(layer, 'col1', existingFields); const instance = mount( void; onDeleteColumn?: () => void; - existingFields: IndexPatternPrivateState['existingFields']; + existingFields: ExistingFieldsMap[string]; fieldIsInvalid: boolean; markAllFieldsCompatible?: boolean; 'data-test-subj'?: string; @@ -61,9 +61,10 @@ export function FieldSelect({ fields, (field) => currentIndexPattern.getFieldByName(field)?.type === 'document' ); - const containsData = (field: string) => - currentIndexPattern.getFieldByName(field)?.type === 'document' || - fieldExists(existingFields, currentIndexPattern.title, field); + + function containsData(field: string) { + return fieldContainsData(field, currentIndexPattern, existingFields); + } function fieldNamesToOptions(items: string[]) { return items diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx index 80e369526c8e4c..5117e935c59d62 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx @@ -21,8 +21,9 @@ import type { Query } from '@kbn/es-query'; import { GenericIndexPatternColumn, operationDefinitionMap } from '../operations'; import { validateQuery } from '../operations/definitions/filters'; import { QueryInput } from '../query_input'; -import type { IndexPattern, IndexPatternLayer } from '../types'; +import type { IndexPatternLayer } from '../types'; import { useDebouncedValue } from '../../shared_components'; +import type { IndexPattern } from '../../types'; const filterByLabel = i18n.translate('xpack.lens.indexPattern.filterBy.label', { defaultMessage: 'Filter by', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts index 2f703547219ec3..43d9770deb2281 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts @@ -6,7 +6,7 @@ */ import memoizeOne from 'memoize-one'; -import { DatasourceDimensionDropProps, OperationMetadata } from '../../types'; +import { DatasourceDimensionDropProps, IndexPatternMap, OperationMetadata } from '../../types'; import { OperationType } from '../indexpattern'; import { memoizedGetAvailableOperationsByMetadata, OperationFieldTuple } from '../operations'; import { IndexPatternPrivateState } from '../types'; @@ -20,7 +20,7 @@ export interface OperationSupportMatrix { type Props = Pick< DatasourceDimensionDropProps['target'], 'layerId' | 'columnId' | 'filterOperations' -> & { state: IndexPatternPrivateState }; +> & { state: IndexPatternPrivateState; indexPatterns: IndexPatternMap }; function computeOperationMatrix( operationsByMetadata: Array<{ @@ -67,7 +67,7 @@ const memoizedComputeOperationsMatrix = memoizeOne(computeOperationMatrix); // TODO: the support matrix should be available outside of the dimension panel export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix => { const layerId = props.layerId; - const currentIndexPattern = props.state.indexPatterns[props.state.layers[layerId].indexPatternId]; + const currentIndexPattern = props.indexPatterns[props.state.layers[layerId].indexPatternId]; const operationsByMetadata = memoizedGetAvailableOperationsByMetadata(currentIndexPattern); return memoizedComputeOperationsMatrix(operationsByMetadata, props.filterOperations); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/reference_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/reference_editor.tsx index bb1b37bc86d1df..b0aade5b747fb9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/reference_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/reference_editor.tsx @@ -28,13 +28,13 @@ import { } from '../operations'; import { FieldChoiceWithOperationType, FieldSelect } from './field_select'; import { hasField } from '../pure_utils'; +import type { IndexPatternLayer } from '../types'; import type { + ExistingFieldsMap, IndexPattern, IndexPatternField, - IndexPatternLayer, - IndexPatternPrivateState, -} from '../types'; -import type { ParamEditorCustomProps } from '../../types'; + ParamEditorCustomProps, +} from '../../types'; import type { IndexPatternDimensionEditorProps } from './dimension_panel'; import { FormRow } from '../operations/definitions/shared_components'; @@ -83,7 +83,7 @@ export interface ReferenceEditorProps { fieldLabel?: string; operationDefinitionMap: Record; isInline?: boolean; - existingFields: IndexPatternPrivateState['existingFields']; + existingFields: ExistingFieldsMap; dateRange: DateRange; labelAppend?: EuiFormRowProps['labelAppend']; isFullscreen: boolean; @@ -307,7 +307,7 @@ export const ReferenceEditor = (props: ReferenceEditorProps) => { void; uiActions: UiActionsStart; }) { + const [fieldGroupsToShow, fieldFroupsToCollapse] = partition( + Object.entries(fieldGroups), + ([, { showInAccordion }]) => showInAccordion + ); const [pageSize, setPageSize] = useState(PAGINATION_SIZE); const [scrollContainer, setScrollContainer] = useState(undefined); const [accordionState, setAccordionState] = useState>>(() => Object.fromEntries( - Object.entries(fieldGroups) - .filter(([, { showInAccordion }]) => showInAccordion) - .map(([key, { isInitiallyOpen }]) => [key, isInitiallyOpen]) + fieldGroupsToShow.map(([key, { isInitiallyOpen }]) => [key, isInitiallyOpen]) ) ); @@ -116,18 +117,16 @@ export const FieldList = React.memo(function FieldList({ const paginatedFields = useMemo(() => { let remainingItems = pageSize; return Object.fromEntries( - Object.entries(fieldGroups) - .filter(([, { showInAccordion }]) => showInAccordion) - .map(([key, fieldGroup]) => { - if (!accordionState[key] || remainingItems <= 0) { - return [key, []]; - } - const slicedFieldList = fieldGroup.fields.slice(0, remainingItems); - remainingItems = remainingItems - slicedFieldList.length; - return [key, slicedFieldList]; - }) + fieldGroupsToShow.map(([key, fieldGroup]) => { + if (!accordionState[key] || remainingItems <= 0) { + return [key, []]; + } + const slicedFieldList = fieldGroup.fields.slice(0, remainingItems); + remainingItems = remainingItems - slicedFieldList.length; + return [key, slicedFieldList]; + }) ); - }, [pageSize, fieldGroups, accordionState]); + }, [pageSize, fieldGroupsToShow, accordionState]); return (
      - {Object.entries(fieldGroups) - .filter(([, { showInAccordion }]) => !showInAccordion) - .flatMap(([, { fields }]) => - fields.map((field, index) => ( - - )) - )} -
    - - {Object.entries(fieldGroups) - .filter(([, { showInAccordion }]) => showInAccordion) - .map(([key, fieldGroup], index) => ( - - + fields.map((field, index) => ( + { - setAccordionState((s) => ({ - ...s, - [key]: open, - })); - const displayedFieldLength = getDisplayedFieldsLength(fieldGroups, { - ...accordionState, - [key]: open, - }); - setPageSize( - Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) - ); - }} - showExistenceFetchError={existenceFetchFailed} - showExistenceFetchTimeout={existenceFetchTimeout} - renderCallout={ - - } + hideDetails={true} + key={field.name} + itemIndex={index} + groupIndex={0} + dropOntoWorkspace={dropOntoWorkspace} + hasSuggestionForField={hasSuggestionForField} uiActions={uiActions} /> - - - ))} + )) + )} + + + {fieldGroupsToShow.map(([key, fieldGroup], index) => ( + + { + setAccordionState((s) => ({ + ...s, + [key]: open, + })); + const displayedFieldLength = getDisplayedFieldsLength(fieldGroups, { + ...accordionState, + [key]: open, + }); + setPageSize( + Math.max(PAGINATION_SIZE, Math.min(pageSize * 1.5, displayedFieldLength)) + ); + }} + showExistenceFetchError={existenceFetchFailed} + showExistenceFetchTimeout={existenceFetchTimeout} + renderCallout={ + + } + uiActions={uiActions} + /> + + + ))}
    ); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx index cc79941d2cdfec..90be3a9f6e4708 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx @@ -10,7 +10,7 @@ import { EuiLoadingSpinner, EuiNotificationBadge } from '@elastic/eui'; import { coreMock } from '@kbn/core/public/mocks'; import { mountWithIntl, shallowWithIntl } from '@kbn/test-jest-helpers'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; -import { IndexPattern } from './types'; +import { IndexPattern } from '../types'; import { FieldItem } from './field_item'; import { FieldsAccordion, FieldsAccordionProps, FieldItemSharedProps } from './fields_accordion'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx index 33413bf0ba59bb..5db910e6d3effa 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -22,10 +22,8 @@ import { Filter } from '@kbn/es-query'; import type { Query } from '@kbn/es-query'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { IndexPatternField } from './types'; import { FieldItem } from './field_item'; -import { DatasourceDataPanelProps } from '../types'; -import { IndexPattern } from './types'; +import type { DatasourceDataPanelProps, IndexPattern, IndexPatternField } from '../types'; export interface FieldItemSharedProps { core: DatasourceDataPanelProps['core']; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts index 41f2a4df9bcda3..4bf33013b3280a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts @@ -17,7 +17,7 @@ import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { FieldFormatsStart, FieldFormatsSetup } from '@kbn/field-formats-plugin/public'; import type { EditorFrameSetup } from '../types'; -export type { PersistedIndexPatternLayer, IndexPattern, FormulaPublicApi } from './types'; +export type { PersistedIndexPatternLayer, FormulaPublicApi } from './types'; export interface IndexPatternDatasourceSetupPlugins { expressions: ExpressionsSetup; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 8693f8492aebe9..e91aa1b286bec3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -38,6 +38,7 @@ import { import { createMockedFullReference } from './operations/mocks'; import { cloneDeep } from 'lodash'; import { DatatableColumn } from '@kbn/expressions-plugin/common'; +import { createMockFramePublicAPI } from '../mocks'; jest.mock('./loader'); jest.mock('../id_generator'); @@ -166,27 +167,10 @@ const expectedIndexPatterns = { }, }; -type DataViewBaseState = Omit< - IndexPatternPrivateState, - 'indexPatternRefs' | 'indexPatterns' | 'existingFields' | 'isFirstExistenceFetch' ->; - -function enrichBaseState(baseState: DataViewBaseState): IndexPatternPrivateState { - return { - currentIndexPatternId: baseState.currentIndexPatternId, - layers: baseState.layers, - indexPatterns: expectedIndexPatterns, - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - }; -} +const indexPatterns = expectedIndexPatterns; describe('IndexPattern Data Source', () => { - let baseState: Omit< - IndexPatternPrivateState, - 'indexPatternRefs' | 'indexPatterns' | 'existingFields' | 'isFirstExistenceFetch' - >; + let baseState: IndexPatternPrivateState; let indexPatternDatasource: Datasource; beforeEach(() => { @@ -275,9 +259,7 @@ describe('IndexPattern Data Source', () => { describe('#getPersistedState', () => { it('should persist from saved state', async () => { - const state = enrichBaseState(baseState); - - expect(indexPatternDatasource.getPersistableState(state)).toEqual({ + expect(indexPatternDatasource.getPersistableState(baseState)).toEqual({ state: { layers: { first: { @@ -310,12 +292,12 @@ describe('IndexPattern Data Source', () => { describe('#toExpression', () => { it('should generate an empty expression when no columns are selected', async () => { - const state = await indexPatternDatasource.initialize(); - expect(indexPatternDatasource.toExpression(state, 'first')).toEqual(null); + const state = indexPatternDatasource.initialize(); + expect(indexPatternDatasource.toExpression(state, 'first', indexPatterns)).toEqual(null); }); it('should create a table when there is a formula without aggs', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -334,8 +316,7 @@ describe('IndexPattern Data Source', () => { }, }, }; - const state = enrichBaseState(queryBaseState); - expect(indexPatternDatasource.toExpression(state, 'first')).toEqual({ + expect(indexPatternDatasource.toExpression(queryBaseState, 'first', indexPatterns)).toEqual({ chain: [ { function: 'createTable', @@ -353,7 +334,7 @@ describe('IndexPattern Data Source', () => { }); it('should generate an expression for an aggregated query', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -382,9 +363,8 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - expect(indexPatternDatasource.toExpression(state, 'first')).toMatchInlineSnapshot(` + expect(indexPatternDatasource.toExpression(queryBaseState, 'first', indexPatterns)) + .toMatchInlineSnapshot(` Object { "chain": Array [ Object { @@ -508,7 +488,7 @@ describe('IndexPattern Data Source', () => { }); it('should put all time fields used in date_histograms to the esaggs timeFields parameter if not ignoring global time range', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -558,14 +538,16 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(ast.chain[1].arguments.timeFields).toEqual(['timestamp', 'another_datefield']); }); it('should pass time shift parameter to metric agg functions', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -595,14 +577,16 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect((ast.chain[1].arguments.aggs[1] as Ast).chain[0].arguments.timeShift).toEqual(['1d']); }); it('should wrap filtered metrics in filtered metric aggregation', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -644,9 +628,11 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(ast.chain[1].arguments.aggs[0]).toMatchInlineSnapshot(` Object { "chain": Array [ @@ -732,7 +718,7 @@ describe('IndexPattern Data Source', () => { }); it('should add time_scale and format function if time scale is set and supported', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -770,9 +756,11 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; const timeScaleCalls = ast.chain.filter((fn) => fn.function === 'lens_time_scale'); const formatCalls = ast.chain.filter((fn) => fn.function === 'lens_format_column'); expect(timeScaleCalls).toHaveLength(1); @@ -815,7 +803,7 @@ describe('IndexPattern Data Source', () => { }); it('should put column formatters after calculated columns', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -855,16 +843,18 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; const formatIndex = ast.chain.findIndex((fn) => fn.function === 'lens_format_column'); const calculationIndex = ast.chain.findIndex((fn) => fn.function === 'moving_average'); expect(calculationIndex).toBeLessThan(formatIndex); }); it('should rename the output from esaggs when using flat query', () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -905,8 +895,11 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(ast.chain[1].arguments.metricsAtAllLevels).toEqual([false]); expect(JSON.parse(ast.chain[2].arguments.idMap[0] as string)).toEqual({ 'col-0-0': [expect.objectContaining({ id: 'bucket1' })], @@ -916,7 +909,7 @@ describe('IndexPattern Data Source', () => { }); it('should not put date fields used outside date_histograms to the esaggs timeFields parameter', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -945,15 +938,17 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(ast.chain[1].arguments.timeFields).toEqual(['timestamp']); expect(ast.chain[1].arguments.timeFields).not.toContain('timefield'); }); it('should call optimizeEsAggs once per operation for which it is available', () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -1001,11 +996,9 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - const optimizeMock = jest.spyOn(operationDefinitionMap.percentile, 'optimizeEsAggs'); - indexPatternDatasource.toExpression(state, 'first'); + indexPatternDatasource.toExpression(queryBaseState, 'first', indexPatterns); expect(operationDefinitionMap.percentile.optimizeEsAggs).toHaveBeenCalledTimes(1); @@ -1013,7 +1006,7 @@ describe('IndexPattern Data Source', () => { }); it('should update anticipated esAggs column IDs based on the order of the optimized agg expression builders', () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -1066,8 +1059,6 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - const optimizeMock = jest .spyOn(operationDefinitionMap.percentile, 'optimizeEsAggs') .mockImplementation((aggs, esAggsIdMap) => { @@ -1075,7 +1066,11 @@ describe('IndexPattern Data Source', () => { return { aggs: aggs.reverse(), esAggsIdMap }; }); - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(operationDefinitionMap.percentile.optimizeEsAggs).toHaveBeenCalledTimes(1); @@ -1100,7 +1095,7 @@ describe('IndexPattern Data Source', () => { }); it('should collect expression references and append them', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -1126,16 +1121,18 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; // @ts-expect-error we can't isolate just the reference type expect(operationDefinitionMap.testReference.toExpression).toHaveBeenCalled(); expect(ast.chain[3]).toEqual('mock'); }); it('should keep correct column mapping keys with reference columns present', async () => { - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -1161,9 +1158,11 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; expect(JSON.parse(ast.chain[2].arguments.idMap[0] as string)).toEqual({ 'col-0-0': [ @@ -1176,7 +1175,7 @@ describe('IndexPattern Data Source', () => { it('should topologically sort references', () => { // This is a real example of count() + count() - const queryBaseState: DataViewBaseState = { + const queryBaseState: IndexPatternPrivateState = { currentIndexPatternId: '1', layers: { first: { @@ -1250,9 +1249,11 @@ describe('IndexPattern Data Source', () => { }, }; - const state = enrichBaseState(queryBaseState); - - const ast = indexPatternDatasource.toExpression(state, 'first') as Ast; + const ast = indexPatternDatasource.toExpression( + queryBaseState, + 'first', + indexPatterns + ) as Ast; const chainLength = ast.chain.length; expect(ast.chain[chainLength - 2].arguments.name).toEqual(['math']); expect(ast.chain[chainLength - 1].arguments.id).toEqual(['formula']); @@ -1263,9 +1264,6 @@ describe('IndexPattern Data Source', () => { describe('#insertLayer', () => { it('should insert an empty layer into the previous state', () => { const state = { - indexPatternRefs: [], - existingFields: {}, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -1279,7 +1277,6 @@ describe('IndexPattern Data Source', () => { }, }, currentIndexPatternId: '1', - isFirstExistenceFetch: false, }; expect(indexPatternDatasource.insertLayer(state, 'newLayer')).toEqual({ ...state, @@ -1298,10 +1295,6 @@ describe('IndexPattern Data Source', () => { describe('#removeLayer', () => { it('should remove a layer', () => { const state = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -1333,10 +1326,6 @@ describe('IndexPattern Data Source', () => { it('should list the current layers', () => { expect( indexPatternDatasource.getLayers({ - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -1359,10 +1348,10 @@ describe('IndexPattern Data Source', () => { let publicAPI: DatasourcePublicAPI; beforeEach(async () => { - const initialState = enrichBaseState(baseState); publicAPI = indexPatternDatasource.getPublicAPI({ - state: initialState, + state: baseState, layerId: 'first', + indexPatterns, }); }); @@ -1378,7 +1367,7 @@ describe('IndexPattern Data Source', () => { it('should skip columns that are being referenced', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1407,6 +1396,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getTableSpec()).toEqual([expect.objectContaining({ columnId: 'col2' })]); @@ -1415,7 +1405,7 @@ describe('IndexPattern Data Source', () => { it('should collect all fields (also from referenced columns)', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1444,6 +1434,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); // The cumulative sum column has no field, but it references a sum column (hidden) which has it // The getTableSpec() should walk the reference tree and assign all fields to the root column @@ -1453,7 +1444,7 @@ describe('IndexPattern Data Source', () => { it('should collect and organize fields per visible column', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1494,6 +1485,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); // col1 is skipped as referenced but its field gets inherited by col2 @@ -1522,7 +1514,7 @@ describe('IndexPattern Data Source', () => { it('should return null for referenced columns', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1551,6 +1543,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getOperationForColumnId('col1')).toEqual(null); }); @@ -1566,7 +1559,7 @@ describe('IndexPattern Data Source', () => { it('should return all filters in metrics, grouped by language', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1595,6 +1588,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -1607,7 +1601,7 @@ describe('IndexPattern Data Source', () => { it('should ignore empty filtered metrics', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1627,6 +1621,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { kuery: [], lucene: [] }, @@ -1636,7 +1631,7 @@ describe('IndexPattern Data Source', () => { it('shuold collect top values fields as kuery existence filters if no data is provided', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1672,6 +1667,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -1690,7 +1686,7 @@ describe('IndexPattern Data Source', () => { it('shuold collect top values fields and terms as kuery filters if data is provided', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1726,6 +1722,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); const data = { first: { @@ -1760,7 +1757,7 @@ describe('IndexPattern Data Source', () => { it('shuold collect top values fields and terms and carefully handle empty string values', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1796,6 +1793,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); const data = { first: { @@ -1830,7 +1828,7 @@ describe('IndexPattern Data Source', () => { it('should ignore top values fields if other/missing option is enabled', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1867,6 +1865,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { kuery: [], lucene: [] }, @@ -1876,7 +1875,7 @@ describe('IndexPattern Data Source', () => { it('should collect custom ranges as kuery filters', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1912,6 +1911,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -1930,7 +1930,7 @@ describe('IndexPattern Data Source', () => { it('should collect custom ranges as kuery filters as partial', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -1974,6 +1974,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -1989,7 +1990,7 @@ describe('IndexPattern Data Source', () => { it('should collect filters within filters operation grouped by language', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -2035,6 +2036,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -2059,7 +2061,7 @@ describe('IndexPattern Data Source', () => { it('should ignore filtered metrics if at least one metric is unfiltered', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -2087,6 +2089,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { kuery: [], lucene: [] }, @@ -2096,7 +2099,7 @@ describe('IndexPattern Data Source', () => { it('should ignore filtered metrics if at least one metric is unfiltered in formula', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -2159,6 +2162,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { kuery: [], lucene: [] }, @@ -2168,7 +2172,7 @@ describe('IndexPattern Data Source', () => { it('should support complete scenarios', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -2225,6 +2229,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -2254,7 +2259,7 @@ describe('IndexPattern Data Source', () => { it('should avoid duplicate filters when formula has a global filter', () => { publicAPI = indexPatternDatasource.getPublicAPI({ state: { - ...enrichBaseState(baseState), + ...baseState, layers: { first: { indexPatternId: '1', @@ -2319,6 +2324,7 @@ describe('IndexPattern Data Source', () => { }, }, layerId: 'first', + indexPatterns, }); expect(publicAPI.getFilters()).toEqual({ enabled: { @@ -2360,10 +2366,6 @@ describe('IndexPattern Data Source', () => { (getErrorMessages as jest.Mock).mockClear(); (getErrorMessages as jest.Mock).mockReturnValueOnce(['error 1', 'error 2']); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2373,7 +2375,7 @@ describe('IndexPattern Data Source', () => { }, currentIndexPatternId: '1', }; - expect(indexPatternDatasource.getErrorMessages(state)).toEqual([ + expect(indexPatternDatasource.getErrorMessages(state, indexPatterns)).toEqual([ { longMessage: 'error 1', shortMessage: '' }, { longMessage: 'error 2', shortMessage: '' }, ]); @@ -2384,10 +2386,6 @@ describe('IndexPattern Data Source', () => { (getErrorMessages as jest.Mock).mockClear(); (getErrorMessages as jest.Mock).mockReturnValueOnce(['error 1', 'error 2']); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2402,7 +2400,7 @@ describe('IndexPattern Data Source', () => { }, currentIndexPatternId: '1', }; - expect(indexPatternDatasource.getErrorMessages(state)).toEqual([ + expect(indexPatternDatasource.getErrorMessages(state, indexPatterns)).toEqual([ { longMessage: 'Layer 1 error: error 1', shortMessage: '' }, { longMessage: 'Layer 1 error: error 2', shortMessage: '' }, ]); @@ -2431,10 +2429,6 @@ describe('IndexPattern Data Source', () => { }; state = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2530,6 +2524,14 @@ describe('IndexPattern Data Source', () => { ], }, }, + dataViews: { + ...createMockFramePublicAPI().dataViews, + indexPatterns: expectedIndexPatterns, + indexPatternRefs: Object.values(expectedIndexPatterns).map(({ id, title }) => ({ + id, + title, + })), + }, } as unknown as FramePublicAPI; }); @@ -2570,10 +2572,6 @@ describe('IndexPattern Data Source', () => { (getErrorMessages as jest.Mock).mockReturnValueOnce(['error 1', 'error 2']); state = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2589,7 +2587,7 @@ describe('IndexPattern Data Source', () => { currentIndexPatternId: '1', }; - expect(indexPatternDatasource.getErrorMessages(state)).toEqual([ + expect(indexPatternDatasource.getErrorMessages(state, indexPatterns)).toEqual([ { longMessage: 'Layer 1 error: error 1', shortMessage: '' }, { longMessage: 'Layer 1 error: error 2', shortMessage: '' }, ]); @@ -2602,10 +2600,6 @@ describe('IndexPattern Data Source', () => { expect( indexPatternDatasource.updateStateOnCloseDimension!({ state: { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2632,10 +2626,6 @@ describe('IndexPattern Data Source', () => { it('should clear all incomplete columns', () => { const state = { - indexPatternRefs: [], - existingFields: {}, - isFirstExistenceFetch: false, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -2670,7 +2660,7 @@ describe('IndexPattern Data Source', () => { }); describe('#isTimeBased', () => { it('should return true if date histogram exists in any layer', () => { - let state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2722,18 +2712,16 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); - state = { - ...state, - indexPatterns: { - ...state.indexPatterns, - '1': { ...state.indexPatterns['1'], timeFieldName: undefined }, - }, - }; - expect(indexPatternDatasource.isTimeBased(state)).toEqual(true); + } as IndexPatternPrivateState; + expect( + indexPatternDatasource.isTimeBased(state, { + ...indexPatterns, + '1': { ...indexPatterns['1'], timeFieldName: undefined }, + }) + ).toEqual(true); }); it('should return false if date histogram exists but is detached from global time range in every layer', () => { - let state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2786,18 +2774,16 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); - state = { - ...state, - indexPatterns: { - ...state.indexPatterns, - '1': { ...state.indexPatterns['1'], timeFieldName: undefined }, - }, - }; - expect(indexPatternDatasource.isTimeBased(state)).toEqual(false); + } as IndexPatternPrivateState; + expect( + indexPatternDatasource.isTimeBased(state, { + ...indexPatterns, + '1': { ...indexPatterns['1'], timeFieldName: undefined }, + }) + ).toEqual(false); }); it('should return false if date histogram does not exist in any layer', () => { - let state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2814,18 +2800,16 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); - state = { - ...state, - indexPatterns: { - ...state.indexPatterns, - '1': { ...state.indexPatterns['1'], timeFieldName: undefined }, - }, - }; - expect(indexPatternDatasource.isTimeBased(state)).toEqual(false); + } as IndexPatternPrivateState; + expect( + indexPatternDatasource.isTimeBased(state, { + ...indexPatterns, + '1': { ...indexPatterns['1'], timeFieldName: undefined }, + }) + ).toEqual(false); }); it('should return true if the index pattern is time based even if date histogram does not exist in any layer', () => { - const state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2842,14 +2826,14 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); - expect(indexPatternDatasource.isTimeBased(state)).toEqual(true); + } as IndexPatternPrivateState; + expect(indexPatternDatasource.isTimeBased(state, indexPatterns)).toEqual(true); }); }); describe('#initializeDimension', () => { it('should return the same state if no static value is passed', () => { - const state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2866,9 +2850,9 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); + } as IndexPatternPrivateState; expect( - indexPatternDatasource.initializeDimension!(state, 'first', { + indexPatternDatasource.initializeDimension!(state, 'first', indexPatterns, { columnId: 'newStatic', groupId: 'a', }) @@ -2876,7 +2860,7 @@ describe('IndexPattern Data Source', () => { }); it('should add a new static value column if a static value is passed', () => { - const state = enrichBaseState({ + const state = { currentIndexPatternId: '1', layers: { first: { @@ -2893,9 +2877,9 @@ describe('IndexPattern Data Source', () => { }, }, }, - }); + } as IndexPatternPrivateState; expect( - indexPatternDatasource.initializeDimension!(state, 'first', { + indexPatternDatasource.initializeDimension!(state, 'first', indexPatterns, { columnId: 'newStatic', groupId: 'a', staticValue: 0, // use a falsy value to check also this corner case diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 7aafe81fc33fae..a2ab9fd2382150 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -28,17 +28,20 @@ import type { DatasourceDataPanelProps, DatasourceLayerPanelProps, PublicAPIProps, - InitializationOptions, OperationDescriptor, FramePublicAPI, + IndexPatternField, + IndexPattern, + IndexPatternRef, } from '../types'; import { - loadInitialState, changeIndexPattern, changeLayerIndexPattern, extractReferences, injectReferences, - loadIndexPatterns, + loadInitialState, + onRefreshIndexPattern, + triggerActionOnIndexPatternChange, } from './loader'; import { toExpression } from './to_expression'; import { @@ -67,14 +70,9 @@ import { TermsIndexPatternColumn, } from './operations'; import { getReferenceRoot } from './operations/layer_helpers'; -import { - IndexPatternField, - IndexPatternPrivateState, - IndexPatternPersistedState, - IndexPattern, -} from './types'; +import { IndexPatternPrivateState, IndexPatternPersistedState } from './types'; import { mergeLayer } from './state_helpers'; -import { Datasource, StateSetter, VisualizeEditorContext } from '../types'; +import { Datasource, VisualizeEditorContext } from '../types'; import { deleteColumn, isReferenced } from './operations'; import { GeoFieldWorkspacePanel } from '../editor_frame_service/editor_frame/workspace_panel/geo_field_workspace_panel'; import { DraggingIdentifier } from '../drag_drop'; @@ -137,48 +135,28 @@ export function getIndexPatternDatasource({ uiActions: UiActionsStart; }) { const uiSettings = core.uiSettings; - const onIndexPatternLoadError = (err: Error) => - core.notifications.toasts.addError(err, { - title: i18n.translate('xpack.lens.indexPattern.dataViewLoadError', { - defaultMessage: 'Error loading data view', - }), - }); - - const indexPatternsService = dataViews; - - const handleChangeIndexPattern = ( - id: string, - state: IndexPatternPrivateState, - setState: StateSetter - ) => { - changeIndexPattern({ - id, - state, - setState, - onError: onIndexPatternLoadError, - storage, - indexPatternsService, - }); - }; + + const DATASOURCE_ID = 'indexpattern'; // Not stateful. State is persisted to the frame const indexPatternDatasource: Datasource = { - id: 'indexpattern', + id: DATASOURCE_ID, - async initialize( + initialize( persistedState?: IndexPatternPersistedState, references?: SavedObjectReference[], initialContext?: VisualizeFieldContext | VisualizeEditorContext, - options?: InitializationOptions + indexPatternRefs?: IndexPatternRef[], + indexPatterns?: Record ) { return loadInitialState({ persistedState, references, defaultIndexPatternId: core.uiSettings.get('defaultIndex'), storage, - indexPatternsService, initialContext, - options, + indexPatternRefs, + indexPatterns, }); }, @@ -224,8 +202,8 @@ export function getIndexPatternDatasource({ return Object.keys(state.layers); }, - removeColumn({ prevState, layerId, columnId }) { - const indexPattern = prevState.indexPatterns[prevState.layers[layerId]?.indexPatternId]; + removeColumn({ prevState, layerId, columnId, indexPatterns }) { + const indexPattern = indexPatterns[prevState.layers[layerId]?.indexPatternId]; return mergeLayer({ state: prevState, layerId, @@ -237,8 +215,8 @@ export function getIndexPatternDatasource({ }); }, - initializeDimension(state, layerId, { columnId, groupId, staticValue }) { - const indexPattern = state.indexPatterns[state.layers[layerId]?.indexPatternId]; + initializeDimension(state, layerId, indexPatterns, { columnId, groupId, staticValue }) { + const indexPattern = indexPatterns[state.layers[layerId]?.indexPatternId]; if (staticValue == null) { return state; } @@ -259,25 +237,27 @@ export function getIndexPatternDatasource({ }); }, - toExpression: (state, layerId) => toExpression(state, layerId, uiSettings), + toExpression: (state, layerId, indexPatterns) => + toExpression(state, layerId, indexPatterns, uiSettings), renderDataPanel( domElement: Element, props: DatasourceDataPanelProps ) { + const { onChangeIndexPattern, ...otherProps } = props; render( , @@ -317,10 +297,10 @@ export function getIndexPatternDatasource({ return columnLabelMap; }, - isValidColumn: (state: IndexPatternPrivateState, layerId: string, columnId: string) => { + isValidColumn: (state, indexPatterns, layerId, columnId) => { const layer = state.layers[layerId]; - return !isColumnInvalid(layer, columnId, state.indexPatterns[layer.indexPatternId]); + return !isColumnInvalid(layer, columnId, indexPatterns[layer.indexPatternId]); }, renderDimensionTrigger: ( @@ -398,23 +378,20 @@ export function getIndexPatternDatasource({ domElement: Element, props: DatasourceLayerPanelProps ) => { + const { onChangeIndexPattern, ...otherProps } = props; render( { - changeLayerIndexPattern({ + triggerActionOnIndexPatternChange({ indexPatternId, - setState: props.setState, state: props.state, layerId: props.layerId, - onError: onIndexPatternLoadError, - replaceIfPossible: true, - storage, - indexPatternsService, uiActions, }); + onChangeIndexPattern(indexPatternId, DATASOURCE_ID, props.layerId); }} - {...props} + {...otherProps} /> , domElement @@ -457,9 +434,26 @@ export function getIndexPatternDatasource({ }, updateCurrentIndexPatternId: ({ state, indexPatternId, setState }) => { - handleChangeIndexPattern(indexPatternId, state, setState); + setState({ + ...state, + currentIndexPatternId: indexPatternId, + }); }, + onRefreshIndexPattern, + onIndexPatternChange(state, indexPatterns, indexPatternId, layerId) { + if (layerId) { + return changeLayerIndexPattern({ + indexPatternId, + layerId, + state, + replaceIfPossible: true, + storage, + indexPatterns, + }); + } + return changeIndexPattern({ indexPatternId, state, storage, indexPatterns }); + }, getRenderEventCounters(state: IndexPatternPrivateState): string[] { const additionalEvents = { time_shift: false, @@ -490,26 +484,6 @@ export function getIndexPatternDatasource({ ].map((item) => `dimension_${item}`); }, - refreshIndexPatternsList: async ({ indexPatternId, setState }) => { - const newlyMappedIndexPattern = await loadIndexPatterns({ - indexPatternsService: dataViews, - cache: {}, - patterns: [indexPatternId], - }); - const indexPatternRefs = await dataViews.getIdsWithTitle(); - const indexPattern = newlyMappedIndexPattern[indexPatternId]; - setState((s) => { - return { - ...s, - indexPatterns: { - ...s.indexPatterns, - [indexPattern.id]: indexPattern, - }, - indexPatternRefs, - }; - }); - }, - // Reset the temporary invalid state when closing the editor, but don't // update the state if it's not needed updateStateOnCloseDimension: ({ state, layerId }) => { @@ -524,13 +498,13 @@ export function getIndexPatternDatasource({ }); }, - getPublicAPI({ state, layerId }: PublicAPIProps) { + getPublicAPI({ state, layerId, indexPatterns }: PublicAPIProps) { const columnLabelMap = indexPatternDatasource.uniqueLabels(state); const layer = state.layers[layerId]; const visibleColumnIds = layer.columnOrder.filter((colId) => !isReferenced(layer, colId)); return { - datasourceId: 'indexpattern', + datasourceId: DATASOURCE_ID, getTableSpec: () => { // consider also referenced columns in this case // but map fields to the top referencing column @@ -560,7 +534,7 @@ export function getIndexPatternDatasource({ return columnToOperation( layer.columns[columnId], columnLabelMap[columnId], - state.indexPatterns[layer.indexPatternId] + indexPatterns[layer.indexPatternId] ); } } @@ -572,7 +546,7 @@ export function getIndexPatternDatasource({ layer, visibleColumnIds, activeData?.[layerId], - state.indexPatterns[layer.indexPatternId], + indexPatterns[layer.indexPatternId], timeRange ), getVisualDefaults: () => getVisualDefaultsForLayer(layer), @@ -587,12 +561,13 @@ export function getIndexPatternDatasource({ }, }; }, - getDatasourceSuggestionsForField(state, draggedField, filterLayers) { + getDatasourceSuggestionsForField(state, draggedField, filterLayers, indexPatterns) { return isDraggedField(draggedField) ? getDatasourceSuggestionsForField( state, draggedField.indexPatternId, draggedField.field, + indexPatterns, filterLayers ) : []; @@ -601,23 +576,17 @@ export function getIndexPatternDatasource({ getDatasourceSuggestionsForVisualizeField, getDatasourceSuggestionsForVisualizeCharts, - getErrorMessages(state) { + getErrorMessages(state, indexPatterns) { if (!state) { return; } // Forward the indexpattern as well, as it is required by some operationType checks const layerErrors = Object.entries(state.layers) - .filter(([_, layer]) => !!state.indexPatterns[layer.indexPatternId]) + .filter(([_, layer]) => !!indexPatterns[layer.indexPatternId]) .map(([layerId, layer]) => ( - getErrorMessages( - layer, - state.indexPatterns[layer.indexPatternId], - state, - layerId, - core - ) ?? [] + getErrorMessages(layer, indexPatterns[layer.indexPatternId], state, layerId, core) ?? [] ).map((message) => ({ shortMessage: '', // Not displayed currently longMessage: typeof message === 'string' ? message : message.message, @@ -670,13 +639,13 @@ export function getIndexPatternDatasource({ ), ]; }, - checkIntegrity: (state) => { + checkIntegrity: (state, indexPatterns) => { const ids = Object.values(state.layers || {}).map(({ indexPatternId }) => indexPatternId); - return ids.filter((id) => !state.indexPatterns[id]); + return ids.filter((id) => !indexPatterns[id]); }, - isTimeBased: (state) => { + isTimeBased: (state, indexPatterns) => { if (!state) return false; - const { layers, indexPatterns } = state; + const { layers } = state; return ( Boolean(layers) && Object.values(layers).some((layer) => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index f96a6dbd3340e6..90f59f5470e377 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -163,9 +163,6 @@ const expectedIndexPatterns = { function testInitialState(): IndexPatternPrivateState { return { currentIndexPatternId: '1', - indexPatternRefs: [], - existingFields: {}, - indexPatterns: expectedIndexPatterns, layers: { first: { indexPatternId: '1', @@ -189,7 +186,6 @@ function testInitialState(): IndexPatternPrivateState { }, }, }, - isFirstExistenceFetch: false, }; } @@ -223,13 +219,18 @@ describe('IndexPattern Data Source suggestions', () => { } it('should apply a bucketed aggregation for a string field, using metric for sorting', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithoutLayer(), '1', { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithoutLayer(), + '1', + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -272,13 +273,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('should apply a bucketed aggregation for a date field', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithoutLayer(), '1', { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithoutLayer(), + '1', + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -317,13 +323,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('should select a metric for a number field', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithoutLayer(), '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithoutLayer(), + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -364,35 +375,7 @@ describe('IndexPattern Data Source suggestions', () => { it('should make a metric suggestion for a number field if there is no time field', async () => { const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - isFirstExistenceFetch: false, - indexPatterns: { - 1: { - id: '1', - title: 'no timefield', - hasRestrictions: false, - fields: [ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - getFieldByName: getFieldByNameFactory([ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ]), - }, - }, layers: { first: { indexPatternId: '1', @@ -402,13 +385,44 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getDatasourceSuggestionsForField(state, '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const indexPatterns = { + 1: { + id: '1', + title: 'no timefield', + hasRestrictions: false, + fields: [ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + getFieldByName: getFieldByNameFactory([ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), + }, + }; + + const suggestions = getDatasourceSuggestionsForField( + state, + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + indexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -446,13 +460,18 @@ describe('IndexPattern Data Source suggestions', () => { } it('should apply a bucketed aggregation for a string field, using metric for sorting', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithEmptyLayer(), '1', { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithEmptyLayer(), + '1', + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -495,13 +514,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('should apply a bucketed aggregation for a date field', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithEmptyLayer(), '1', { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithEmptyLayer(), + '1', + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -540,13 +564,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('should select a metric for a number field', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithEmptyLayer(), '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithEmptyLayer(), + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -587,36 +616,7 @@ describe('IndexPattern Data Source suggestions', () => { it('should make a metric suggestion for a number field if there is no time field', async () => { const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - isFirstExistenceFetch: false, - indexPatterns: { - 1: { - id: '1', - title: 'no timefield', - hasRestrictions: false, - fields: [ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - - getFieldByName: getFieldByNameFactory([ - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ]), - }, - }, layers: { previousLayer: { indexPatternId: '1', @@ -626,13 +626,45 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getDatasourceSuggestionsForField(state, '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const indexPatterns = { + 1: { + id: '1', + title: 'no timefield', + hasRestrictions: false, + fields: [ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + + getFieldByName: getFieldByNameFactory([ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), + }, + }; + + const suggestions = getDatasourceSuggestionsForField( + state, + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + indexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -654,13 +686,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('creates a new layer and replaces layer if no match is found', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithEmptyLayer(), '2', { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithEmptyLayer(), + '2', + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -794,7 +831,8 @@ describe('IndexPattern Data Source suggestions', () => { type: 'date', aggregatable: true, searchable: true, - } + }, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -821,13 +859,18 @@ describe('IndexPattern Data Source suggestions', () => { it('puts a date histogram column after the last bucket column on date field', () => { (generateId as jest.Mock).mockReturnValue('newid'); const initialState = stateWithNonEmptyTables(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ state: expect.objectContaining({ @@ -867,13 +910,18 @@ describe('IndexPattern Data Source suggestions', () => { }); it('does not use the same field for bucketing multiple times', () => { - const suggestions = getDatasourceSuggestionsForField(stateWithNonEmptyTables(), '1', { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + stateWithNonEmptyTables(), + '1', + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toHaveLength(0); }); @@ -881,13 +929,18 @@ describe('IndexPattern Data Source suggestions', () => { it('appends a terms column with default size on string field', () => { (generateId as jest.Mock).mockReturnValue('newid'); const initialState = stateWithNonEmptyTables(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ state: expect.objectContaining({ @@ -913,13 +966,18 @@ describe('IndexPattern Data Source suggestions', () => { it('suggests both replacing and adding metric if only one other metric is set', () => { (generateId as jest.Mock).mockReturnValue('newid'); const initialState = stateWithNonEmptyTables(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ state: expect.objectContaining({ @@ -988,13 +1046,18 @@ describe('IndexPattern Data Source suggestions', () => { }, }, }; - const suggestions = getDatasourceSuggestionsForField(modifiedState, '1', { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + modifiedState, + '1', + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1019,26 +1082,36 @@ describe('IndexPattern Data Source suggestions', () => { it('skips duplicates when the field is already in use', () => { const initialState = stateWithNonEmptyTables(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).not.toContain(expect.objectContaining({ changeType: 'extended' })); }); it('skips metric only suggestion when the field is already in use', () => { const initialState = stateWithNonEmptyTables(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect( suggestions.some( @@ -1070,7 +1143,12 @@ describe('IndexPattern Data Source suggestions', () => { }, }, }; - const suggestions = getDatasourceSuggestionsForField(modifiedState, '1', documentField); + const suggestions = getDatasourceSuggestionsForField( + modifiedState, + '1', + documentField, + expectedIndexPatterns + ); expect(suggestions).not.toContain(expect.objectContaining({ changeType: 'extended' })); }); @@ -1114,7 +1192,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; const suggestions = getSuggestionSubset( - getDatasourceSuggestionsForField(modifiedState, '1', documentField) + getDatasourceSuggestionsForField(modifiedState, '1', documentField, expectedIndexPatterns) ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1174,7 +1252,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; const suggestions = getSuggestionSubset( - getDatasourceSuggestionsForField(modifiedState, '1', documentField) + getDatasourceSuggestionsForField(modifiedState, '1', documentField, expectedIndexPatterns) ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1261,6 +1339,7 @@ describe('IndexPattern Data Source suggestions', () => { modifiedState, '1', documentField, + expectedIndexPatterns, (layerId) => layerId !== 'referenceLineLayer' ) ); @@ -1323,21 +1402,26 @@ describe('IndexPattern Data Source suggestions', () => { it('suggests on the layer that matches by indexPatternId', () => { const initialState = stateWithCurrentIndexPattern(); - const suggestions = getDatasourceSuggestionsForField(initialState, '2', { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', + const suggestions = getDatasourceSuggestionsForField( + initialState, + '2', + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, }, }, - }); + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1378,13 +1462,18 @@ describe('IndexPattern Data Source suggestions', () => { it('suggests on the layer with the fewest columns that matches by indexPatternId', () => { const initialState = stateWithCurrentIndexPattern(); - const suggestions = getDatasourceSuggestionsForField(initialState, '1', { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }); + const suggestions = getDatasourceSuggestionsForField( + initialState, + '1', + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1450,14 +1539,19 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toStrictEqual([]); }); it('should apply a count metric, with a timeseries bucket', () => { - const suggestions = getDatasourceSuggestionsForVisualizeCharts(stateWithoutLayer(), context); + const suggestions = getDatasourceSuggestionsForVisualizeCharts( + stateWithoutLayer(), + context, + expectedIndexPatterns + ); expect(suggestions).toContainEqual( expect.objectContaining({ @@ -1505,7 +1599,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1555,7 +1650,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1621,7 +1717,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1703,7 +1800,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1787,7 +1885,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1856,7 +1955,8 @@ describe('IndexPattern Data Source suggestions', () => { ]; const suggestions = getDatasourceSuggestionsForVisualizeCharts( stateWithoutLayer(), - updatedContext + updatedContext, + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1906,7 +2006,8 @@ describe('IndexPattern Data Source suggestions', () => { const suggestions = getDatasourceSuggestionsForVisualizeField( stateWithoutLayer(), '1', - 'field_not_exist' + 'field_not_exist', + expectedIndexPatterns ); expect(suggestions).toEqual([]); @@ -1916,7 +2017,8 @@ describe('IndexPattern Data Source suggestions', () => { const suggestions = getDatasourceSuggestionsForVisualizeField( stateWithoutLayer(), '1', - 'source' + 'source', + expectedIndexPatterns ); expect(suggestions).toContainEqual( @@ -1961,20 +2063,19 @@ describe('IndexPattern Data Source suggestions', () => { describe('#getDatasourceSuggestionsFromCurrentState', () => { it('returns no suggestions if there are no columns', () => { expect( - getDatasourceSuggestionsFromCurrentState({ - isFirstExistenceFetch: false, - indexPatternRefs: [], - existingFields: {}, - indexPatterns: expectedIndexPatterns, - layers: { - first: { - indexPatternId: '1', - columnOrder: [], - columns: {}, + getDatasourceSuggestionsFromCurrentState( + { + layers: { + first: { + indexPatternId: '1', + columnOrder: [], + columns: {}, + }, }, + currentIndexPatternId: '1', }, - currentIndexPatternId: '1', - }) + expectedIndexPatterns + ) ).toEqual([]); }); @@ -2008,7 +2109,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getDatasourceSuggestionsFromCurrentState(state); + const result = getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns); expect(result).toContainEqual( expect.objectContaining({ @@ -2094,7 +2195,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - expect(getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state))).toContainEqual( + expect( + getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns)) + ).toContainEqual( expect.objectContaining({ table: { isMultiRow: true, @@ -2167,7 +2270,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - expect(getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state))).toContainEqual( + expect( + getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns)) + ).toContainEqual( expect.objectContaining({ table: { isMultiRow: true, @@ -2268,7 +2373,11 @@ describe('IndexPattern Data Source suggestions', () => { expect( getSuggestionSubset( - getDatasourceSuggestionsFromCurrentState(state, (layerId) => layerId !== 'referenceLine') + getDatasourceSuggestionsFromCurrentState( + state, + expectedIndexPatterns, + (layerId) => layerId !== 'referenceLine' + ) ) ).toContainEqual( expect.objectContaining({ @@ -2352,7 +2461,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - expect(getDatasourceSuggestionsFromCurrentState(state)).not.toContainEqual( + expect( + getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns) + ).not.toContainEqual( expect.objectContaining({ table: { isMultiRow: true, @@ -2398,7 +2509,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - expect(getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state))).toContainEqual( + expect( + getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns)) + ).toContainEqual( expect.objectContaining({ table: { changeType: 'extended', @@ -2467,9 +2580,8 @@ describe('IndexPattern Data Source suggestions', () => { }, }, }; - const suggestions = getDatasourceSuggestionsFromCurrentState({ - ...state, - indexPatterns: { 1: { ...state.indexPatterns['1'], timeFieldName: undefined } }, + const suggestions = getDatasourceSuggestionsFromCurrentState(state, { + 1: { ...expectedIndexPatterns['1'], timeFieldName: undefined }, }); suggestions.forEach((suggestion) => expect(suggestion.table.columns.length).toBe(1)); }); @@ -2477,9 +2589,8 @@ describe('IndexPattern Data Source suggestions', () => { it("should not propose an over time suggestion if there's a top values aggregation with an high size", () => { const initialState = testInitialState(); (initialState.layers.first.columns.col1 as TermsIndexPatternColumn).params!.size = 6; - const suggestions = getDatasourceSuggestionsFromCurrentState({ - ...initialState, - indexPatterns: { 1: { ...initialState.indexPatterns['1'], timeFieldName: undefined } }, + const suggestions = getDatasourceSuggestionsFromCurrentState(initialState, { + 1: { ...expectedIndexPatterns['1'], timeFieldName: undefined }, }); suggestions.forEach((suggestion) => expect(suggestion.table.columns.length).toBe(1)); }); @@ -2522,9 +2633,8 @@ describe('IndexPattern Data Source suggestions', () => { }, }, }; - const suggestions = getDatasourceSuggestionsFromCurrentState({ - ...state, - indexPatterns: { 1: { ...state.indexPatterns['1'], timeFieldName: undefined } }, + const suggestions = getDatasourceSuggestionsFromCurrentState(state, { + 1: { ...expectedIndexPatterns['1'], timeFieldName: undefined }, }); suggestions.forEach((suggestion) => { const firstBucket = suggestion.table.columns.find(({ columnId }) => columnId === 'col1'); @@ -2572,19 +2682,7 @@ describe('IndexPattern Data Source suggestions', () => { }, ]; const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - indexPatterns: { - 1: { - id: '1', - title: 'my-fake-index-pattern', - hasRestrictions: false, - fields, - getFieldByName: getFieldByNameFactory(fields), - }, - }, - isFirstExistenceFetch: false, layers: { first: { ...initialState.layers.first, @@ -2655,7 +2753,15 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getDatasourceSuggestionsFromCurrentState(state); + const suggestions = getDatasourceSuggestionsFromCurrentState(state, { + 1: { + id: '1', + title: 'my-fake-index-pattern', + hasRestrictions: false, + fields, + getFieldByName: getFieldByNameFactory(fields), + }, + }); // 3 bucket cols, 2 metric cols isTableWithBucketColumns(suggestions[0], ['col1', 'col2', 'col3', 'col4', 'col5'], 3); @@ -2681,50 +2787,7 @@ describe('IndexPattern Data Source suggestions', () => { it('returns an only metric version of a given table, but does not include current state as reduced', () => { const initialState = testInitialState(); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - indexPatterns: { - 1: { - id: '1', - title: 'my-fake-index-pattern', - hasRestrictions: false, - fields: [ - { - name: 'field1', - displayName: 'field1', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'field2', - displayName: 'field2', - type: 'date', - aggregatable: true, - searchable: true, - }, - ], - - getFieldByName: getFieldByNameFactory([ - { - name: 'field1', - displayName: 'field1', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'field2', - displayName: 'field2', - type: 'date', - aggregatable: true, - searchable: true, - }, - ]), - }, - }, - isFirstExistenceFetch: false, layers: { first: { ...initialState.layers.first, @@ -2754,7 +2817,50 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state)); + const indexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + hasRestrictions: false, + fields: [ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'field2', + displayName: 'field2', + type: 'date', + aggregatable: true, + searchable: true, + }, + ], + + getFieldByName: getFieldByNameFactory([ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'field2', + displayName: 'field2', + type: 'date', + aggregatable: true, + searchable: true, + }, + ]), + }, + }; + + const suggestions = getSuggestionSubset( + getDatasourceSuggestionsFromCurrentState(state, indexPatterns) + ); expect(suggestions).not.toContainEqual( expect.objectContaining({ table: expect.objectContaining({ @@ -2787,35 +2893,7 @@ describe('IndexPattern Data Source suggestions', () => { it('returns an alternative metric for an only-metric table', () => { const initialState = testInitialState(); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - indexPatterns: { - 1: { - id: '1', - title: 'my-fake-index-pattern', - hasRestrictions: false, - fields: [ - { - name: 'field1', - displayName: 'field1', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - getFieldByName: getFieldByNameFactory([ - { - name: 'field1', - displayName: 'field1', - type: 'number', - aggregatable: true, - searchable: true, - }, - ]), - }, - }, - isFirstExistenceFetch: false, layers: { first: { ...initialState.layers.first, @@ -2834,7 +2912,35 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state)); + const indexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + hasRestrictions: false, + fields: [ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + getFieldByName: getFieldByNameFactory([ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), + }, + }; + + const suggestions = getSuggestionSubset( + getDatasourceSuggestionsFromCurrentState(state, indexPatterns) + ); expect(suggestions).toContainEqual( expect.objectContaining({ table: expect.objectContaining({ @@ -2851,11 +2957,7 @@ describe('IndexPattern Data Source suggestions', () => { it('contains a reordering suggestion when there are exactly 2 buckets', () => { const initialState = testInitialState(); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - indexPatterns: expectedIndexPatterns, - isFirstExistenceFetch: false, layers: { first: { ...initialState.layers.first, @@ -2894,7 +2996,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getDatasourceSuggestionsFromCurrentState(state); + const suggestions = getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns); expect(suggestions).toContainEqual( expect.objectContaining({ table: expect.objectContaining({ @@ -2907,11 +3009,7 @@ describe('IndexPattern Data Source suggestions', () => { it('will generate suggestions even if there are errors from missing fields', () => { const initialState = testInitialState(); const state: IndexPatternPrivateState = { - indexPatternRefs: [], - existingFields: {}, currentIndexPatternId: '1', - indexPatterns: expectedIndexPatterns, - isFirstExistenceFetch: false, layers: { first: { ...initialState.layers.first, @@ -2932,7 +3030,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const suggestions = getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state)); + const suggestions = getSuggestionSubset( + getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns) + ); expect(suggestions).toContainEqual( expect.objectContaining({ table: { @@ -3006,7 +3106,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state)); + const result = getSuggestionSubset( + getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns) + ); expect(result).toContainEqual( expect.objectContaining({ @@ -3091,7 +3193,9 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getSuggestionSubset(getDatasourceSuggestionsFromCurrentState(state)); + const result = getSuggestionSubset( + getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns) + ); expect(result).toContainEqual( expect.objectContaining({ @@ -3235,7 +3339,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getDatasourceSuggestionsFromCurrentState(state); + const result = getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns); // only generate suggestions for top level metrics + only first metric with all buckets expect( @@ -3316,7 +3420,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getDatasourceSuggestionsFromCurrentState(state); + const result = getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns); // only generate suggestions for top level metrics expect( @@ -3366,7 +3470,7 @@ describe('IndexPattern Data Source suggestions', () => { }, }; - const result = getDatasourceSuggestionsFromCurrentState(state); + const result = getDatasourceSuggestionsFromCurrentState(state, expectedIndexPatterns); expect( result.filter((suggestion) => suggestion.table.changeType === 'unchanged').length diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index 720c917dcbc53b..319c309cac0363 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -9,7 +9,13 @@ import { flatten, minBy, pick, mapValues, partition } from 'lodash'; import { i18n } from '@kbn/i18n'; import type { VisualizeEditorLayersContext } from '@kbn/visualizations-plugin/public'; import { generateId } from '../id_generator'; -import type { DatasourceSuggestion, TableChangeType } from '../types'; +import type { + DatasourceSuggestion, + IndexPattern, + IndexPatternField, + IndexPatternMap, + TableChangeType, +} from '../types'; import { columnToOperation } from './indexpattern'; import { insertNewColumn, @@ -28,12 +34,7 @@ import { hasTermsWithManyBuckets, } from './operations'; import { hasField } from './pure_utils'; -import type { - IndexPattern, - IndexPatternPrivateState, - IndexPatternLayer, - IndexPatternField, -} from './types'; +import type { IndexPatternPrivateState, IndexPatternLayer } from './types'; import { documentField } from './document_field'; export type IndexPatternSuggestion = DatasourceSuggestion; @@ -100,6 +101,7 @@ export function getDatasourceSuggestionsForField( state: IndexPatternPrivateState, indexPatternId: string, field: IndexPatternField, + indexPatterns: IndexPatternMap, filterLayers?: (layerId: string) => boolean ): IndexPatternSuggestion[] { const layers = Object.keys(state.layers); @@ -113,8 +115,20 @@ export function getDatasourceSuggestionsForField( // This generates a set of suggestions where we add a layer. // A second set of suggestions is generated for visualizations that don't work with layers const newId = generateId(); - return getEmptyLayerSuggestionsForField(state, newId, indexPatternId, field).concat( - getEmptyLayerSuggestionsForField({ ...state, layers: {} }, newId, indexPatternId, field) + return getEmptyLayerSuggestionsForField( + state, + newId, + indexPatternId, + field, + indexPatterns + ).concat( + getEmptyLayerSuggestionsForField( + { ...state, layers: {} }, + newId, + indexPatternId, + field, + indexPatterns + ) ); } else { // The field we're suggesting on matches an existing layer. In this case we find the layer with @@ -125,9 +139,15 @@ export function getDatasourceSuggestionsForField( (layerId) => state.layers[layerId].columnOrder.length ) as string; if (state.layers[mostEmptyLayerId].columnOrder.length === 0) { - return getEmptyLayerSuggestionsForField(state, mostEmptyLayerId, indexPatternId, field); + return getEmptyLayerSuggestionsForField( + state, + mostEmptyLayerId, + indexPatternId, + field, + indexPatterns + ); } else { - return getExistingLayerSuggestionsForField(state, mostEmptyLayerId, field); + return getExistingLayerSuggestionsForField(state, mostEmptyLayerId, field, indexPatterns); } } } @@ -135,24 +155,26 @@ export function getDatasourceSuggestionsForField( // Called when the user navigates from Visualize editor to Lens export function getDatasourceSuggestionsForVisualizeCharts( state: IndexPatternPrivateState, - context: VisualizeEditorLayersContext[] + context: VisualizeEditorLayersContext[], + indexPatterns: IndexPatternMap ): IndexPatternSuggestion[] { const layers = Object.keys(state.layers); const layerIds = layers.filter( (id) => state.layers[id].indexPatternId === context[0].indexPatternId ); if (layerIds.length !== 0) return []; - return getEmptyLayersSuggestionsForVisualizeCharts(state, context); + return getEmptyLayersSuggestionsForVisualizeCharts(state, context, indexPatterns); } function getEmptyLayersSuggestionsForVisualizeCharts( state: IndexPatternPrivateState, - context: VisualizeEditorLayersContext[] + context: VisualizeEditorLayersContext[], + indexPatterns: IndexPatternMap ): IndexPatternSuggestion[] { const suggestions: IndexPatternSuggestion[] = []; for (let layerIdx = 0; layerIdx < context.length; layerIdx++) { const layer = context[layerIdx]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = indexPatterns[layer.indexPatternId]; if (!indexPattern) return []; const newId = generateId(); @@ -228,18 +250,31 @@ function createNewTimeseriesLayerWithMetricAggregationFromVizEditor( export function getDatasourceSuggestionsForVisualizeField( state: IndexPatternPrivateState, indexPatternId: string, - fieldName: string + fieldName: string, + indexPatterns: IndexPatternMap ): IndexPatternSuggestion[] { const layers = Object.keys(state.layers); const layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); // Identify the field by the indexPatternId and the fieldName - const indexPattern = state.indexPatterns[indexPatternId]; + const indexPattern = indexPatterns[indexPatternId]; const field = indexPattern.getFieldByName(fieldName); if (layerIds.length !== 0 || !field) return []; const newId = generateId(); - return getEmptyLayerSuggestionsForField(state, newId, indexPatternId, field).concat( - getEmptyLayerSuggestionsForField({ ...state, layers: {} }, newId, indexPatternId, field) + return getEmptyLayerSuggestionsForField( + state, + newId, + indexPatternId, + field, + indexPatterns + ).concat( + getEmptyLayerSuggestionsForField( + { ...state, layers: {} }, + newId, + indexPatternId, + field, + indexPatterns + ) ); } @@ -255,10 +290,11 @@ function getBucketOperation(field: IndexPatternField) { function getExistingLayerSuggestionsForField( state: IndexPatternPrivateState, layerId: string, - field: IndexPatternField + field: IndexPatternField, + indexPatterns: IndexPatternMap ) { const layer = state.layers[layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = indexPatterns[layer.indexPatternId]; const operations = getOperationTypesForField(field); const usableAsBucketOperation = getBucketOperation(field); const fieldInUse = Object.values(layer.columns).some( @@ -369,9 +405,10 @@ function getEmptyLayerSuggestionsForField( state: IndexPatternPrivateState, layerId: string, indexPatternId: string, - field: IndexPatternField + field: IndexPatternField, + indexPatterns: IndexPatternMap ): IndexPatternSuggestion[] { - const indexPattern = state.indexPatterns[indexPatternId]; + const indexPattern = indexPatterns[indexPatternId]; let newLayer: IndexPatternLayer | undefined; const bucketOperation = getBucketOperation(field); if (bucketOperation) { @@ -447,6 +484,7 @@ function createNewLayerWithMetricAggregation( export function getDatasourceSuggestionsFromCurrentState( state: IndexPatternPrivateState, + indexPatterns: IndexPatternMap, filterLayers: (layerId: string) => boolean = () => true ): Array> { const layers = Object.entries(state.layers || {}).filter(([layerId]) => filterLayers(layerId)); @@ -467,7 +505,7 @@ export function getDatasourceSuggestionsFromCurrentState( }) : i18n.translate('xpack.lens.indexPatternSuggestion.removeLayerLabel', { defaultMessage: 'Show only {indexPatternTitle}', - values: { indexPatternTitle: state.indexPatterns[layer.indexPatternId].title }, + values: { indexPatternTitle: indexPatterns[layer.indexPatternId].title }, }); return buildSuggestion({ @@ -495,7 +533,7 @@ export function getDatasourceSuggestionsFromCurrentState( layers .filter(([_id, layer]) => layer.columnOrder.length && layer.indexPatternId) .map(([layerId, layer]) => { - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = indexPatterns[layer.indexPatternId]; const [buckets, metrics, references] = getExistingColumnGroups(layer); const timeDimension = layer.columnOrder.find( (columnId) => @@ -522,7 +560,9 @@ export function getDatasourceSuggestionsFromCurrentState( if (!references.length && metrics.length && buckets.length === 0) { if (timeField && buckets.length < 1 && !hasTermsWithManyBuckets(layer)) { // suggest current metric over time if there is a default time field - suggestions.push(createSuggestionWithDefaultDateHistogram(state, layerId, timeField)); + suggestions.push( + createSuggestionWithDefaultDateHistogram(state, layerId, timeField, indexPatterns) + ); } if (indexPattern) { suggestions.push(...createAlternativeMetricSuggestions(indexPattern, layerId, state)); @@ -541,11 +581,13 @@ export function getDatasourceSuggestionsFromCurrentState( ) { // suggest current configuration over time if there is a default time field // and no time dimension yet - suggestions.push(createSuggestionWithDefaultDateHistogram(state, layerId, timeField)); + suggestions.push( + createSuggestionWithDefaultDateHistogram(state, layerId, timeField, indexPatterns) + ); } if (buckets.length === 2) { - suggestions.push(createChangedNestingSuggestion(state, layerId)); + suggestions.push(createChangedNestingSuggestion(state, layerId, indexPatterns)); } } return suggestions; @@ -553,11 +595,15 @@ export function getDatasourceSuggestionsFromCurrentState( ); } -function createChangedNestingSuggestion(state: IndexPatternPrivateState, layerId: string) { +function createChangedNestingSuggestion( + state: IndexPatternPrivateState, + layerId: string, + indexPatterns: IndexPatternMap +) { const layer = state.layers[layerId]; const [firstBucket, secondBucket, ...rest] = layer.columnOrder; const updatedLayer = { ...layer, columnOrder: [secondBucket, firstBucket, ...rest] }; - const indexPattern = state.indexPatterns[state.currentIndexPatternId]; + const indexPattern = indexPatterns[state.currentIndexPatternId]; const firstBucketColumn = layer.columns[firstBucket]; const firstBucketLabel = (hasField(firstBucketColumn) && @@ -670,10 +716,11 @@ function createAlternativeMetricSuggestions( function createSuggestionWithDefaultDateHistogram( state: IndexPatternPrivateState, layerId: string, - timeField: IndexPatternField + timeField: IndexPatternField, + indexPatterns: IndexPatternMap ) { const layer = state.layers[layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = indexPatterns[layer.indexPatternId]; return buildSuggestion({ state, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx index d0c8e1ffafd693..d481e77bd69a83 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx @@ -12,7 +12,7 @@ import { shallowWithIntl as shallow } from '@kbn/test-jest-helpers'; import { ShallowWrapper } from 'enzyme'; import { EuiSelectable } from '@elastic/eui'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; -import { ChangeIndexPattern } from './change_indexpattern'; +import { ChangeIndexPattern } from '../shared_components/dataview_picker/dataview_picker'; import { getFieldByNameFactory } from './pure_helpers'; import { TermsIndexPatternColumn } from './operations'; @@ -136,14 +136,7 @@ const fieldsThree = [ ]; const initialState: IndexPatternPrivateState = { - indexPatternRefs: [ - { id: '1', title: 'my-fake-index-pattern' }, - { id: '2', title: 'my-fake-restricted-pattern' }, - { id: '3', title: 'my-compatible-pattern' }, - ], - existingFields: {}, currentIndexPatternId: '1', - isFirstExistenceFetch: false, layers: { first: { indexPatternId: '1', @@ -173,32 +166,6 @@ const initialState: IndexPatternPrivateState = { }, }, }, - indexPatterns: { - '1': { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: fieldsOne, - getFieldByName: getFieldByNameFactory(fieldsOne), - }, - '2': { - id: '2', - title: 'my-fake-restricted-pattern', - hasRestrictions: true, - timeFieldName: 'timestamp', - fields: fieldsTwo, - getFieldByName: getFieldByNameFactory(fieldsTwo), - }, - '3': { - id: '3', - title: 'my-compatible-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: fieldsThree, - getFieldByName: getFieldByNameFactory(fieldsThree), - }, - }, }; describe('Layer Data Panel', () => { let defaultProps: IndexPatternLayerPanelProps; @@ -207,8 +174,42 @@ describe('Layer Data Panel', () => { defaultProps = { layerId: 'first', state: initialState, - setState: jest.fn(), - onChangeIndexPattern: jest.fn(async () => {}), + onChangeIndexPattern: jest.fn(), + dataViews: { + indexPatternRefs: [ + { id: '1', title: 'my-fake-index-pattern' }, + { id: '2', title: 'my-fake-restricted-pattern' }, + { id: '3', title: 'my-compatible-pattern' }, + ], + existingFields: {}, + isFirstExistenceFetch: false, + indexPatterns: { + '1': { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsOne, + getFieldByName: getFieldByNameFactory(fieldsOne), + }, + '2': { + id: '2', + title: 'my-fake-restricted-pattern', + hasRestrictions: true, + timeFieldName: 'timestamp', + fields: fieldsTwo, + getFieldByName: getFieldByNameFactory(fieldsTwo), + }, + '3': { + id: '3', + title: 'my-compatible-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsThree, + getFieldByName: getFieldByNameFactory(fieldsThree), + }, + }, + }, }; }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx index 4fd7b920e124b2..9824f70eeddfc0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.tsx @@ -10,7 +10,7 @@ import { I18nProvider } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { DatasourceLayerPanelProps } from '../types'; import { IndexPatternPrivateState } from './types'; -import { ChangeIndexPattern } from './change_indexpattern'; +import { ChangeIndexPattern } from '../shared_components/dataview_picker/dataview_picker'; export interface IndexPatternLayerPanelProps extends DatasourceLayerPanelProps { @@ -18,10 +18,15 @@ export interface IndexPatternLayerPanelProps onChangeIndexPattern: (newId: string) => void; } -export function LayerPanel({ state, layerId, onChangeIndexPattern }: IndexPatternLayerPanelProps) { +export function LayerPanel({ + state, + layerId, + onChangeIndexPattern, + dataViews, +}: IndexPatternLayerPanelProps) { const layer = state.layers[layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; + const indexPattern = dataViews.indexPatterns[layer.indexPatternId]; const notFoundTitleLabel = i18n.translate('xpack.lens.layerPanel.missingDataView', { defaultMessage: 'Data view not found', }); @@ -37,7 +42,7 @@ export function LayerPanel({ state, layerId, onChangeIndexPattern }: IndexPatter fontWeight: 'normal', }} indexPatternId={layer.indexPatternId} - indexPatternRefs={state.indexPatternRefs} + indexPatternRefs={dataViews.indexPatternRefs} isMissingCurrent={!indexPattern} onChangeIndexPattern={onChangeIndexPattern} /> diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index b3806e5c55b15f..3a85a317eec0f3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -5,30 +5,16 @@ * 2.0. */ -import { HttpHandler } from '@kbn/core/public'; -import { last } from 'lodash'; import { loadInitialState, - loadIndexPatterns, changeIndexPattern, changeLayerIndexPattern, - syncExistingFields, extractReferences, injectReferences, } from './loader'; -import { DataViewsContract } from '@kbn/data-views-plugin/public'; -import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; -import { createHttpFetchError } from '@kbn/core-http-browser-mocks'; -import { - IndexPatternPersistedState, - IndexPatternPrivateState, - IndexPatternField, - IndexPattern, -} from './types'; -import { createMockedRestrictedIndexPattern, createMockedIndexPattern } from './mocks'; -import { documentField } from './document_field'; -import { DateHistogramIndexPatternColumn } from './operations'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { IndexPatternPersistedState, IndexPatternPrivateState } from './types'; +import { DateHistogramIndexPatternColumn, TermsIndexPatternColumn } from './operations'; +import { sampleIndexPatterns } from '../indexpattern_service/mocks'; const createMockStorage = (lastData?: Record) => { return { @@ -39,351 +25,29 @@ const createMockStorage = (lastData?: Record) => { }; }; -const indexPattern1 = { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - esTypes: ['keyword'], - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, - esTypes: ['keyword'], - }, - { - name: 'geo.src', - displayName: 'geo.src', - type: 'string', - aggregatable: true, - searchable: true, - esTypes: ['keyword'], - }, - { - name: 'scripted', - displayName: 'Scripted', - type: 'string', - searchable: true, - aggregatable: true, - scripted: true, - lang: 'painless', - script: '1234', - }, - documentField, - ], -} as unknown as IndexPattern; - -const sampleIndexPatternsFromService = { - '1': createMockedIndexPattern(), - '2': createMockedRestrictedIndexPattern(), -}; - -const indexPattern2 = { - id: '2', - title: 'my-fake-restricted-pattern', - timeFieldName: 'timestamp', - hasRestrictions: true, - fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - // Ignored in the UI - histogram: { - agg: 'histogram', - interval: 1000, - }, - average: { - agg: 'avg', - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - scripted: true, - lang: 'painless', - script: '1234', - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - documentField, - ], -} as unknown as IndexPattern; - -const sampleIndexPatterns = { - '1': indexPattern1, - '2': indexPattern2, -}; - -function mockIndexPatternsService() { - return { - get: jest.fn(async (id: '1' | '2') => { - const result = { ...sampleIndexPatternsFromService[id], metaFields: [] }; - if (!result.fields) { - result.fields = []; - } - return result; - }), - getIdsWithTitle: jest.fn(async () => { - return [ - { - id: sampleIndexPatterns[1].id, - title: sampleIndexPatterns[1].title, - }, - { - id: sampleIndexPatterns[2].id, - title: sampleIndexPatterns[2].title, - }, - ]; - }), - } as unknown as Pick; -} +const indexPatternRefs = [ + { + id: sampleIndexPatterns[1].id, + title: sampleIndexPatterns[1].title, + }, + { + id: sampleIndexPatterns[2].id, + title: sampleIndexPatterns[2].title, + }, +]; describe('loader', () => { - describe('loadIndexPatterns', () => { - it('should not load index patterns that are already loaded', async () => { - const cache = await loadIndexPatterns({ - cache: sampleIndexPatterns, - patterns: ['1', '2'], - indexPatternsService: { - get: jest.fn(() => - Promise.reject('mockIndexPatternService.get should not have been called') - ), - getIdsWithTitle: jest.fn(), - } as unknown as Pick, - }); - - expect(cache).toEqual(sampleIndexPatterns); - }); - - it('should load index patterns that are not loaded', async () => { - const cache = await loadIndexPatterns({ - cache: { - '2': sampleIndexPatterns['2'], - }, - patterns: ['1', '2'], - indexPatternsService: mockIndexPatternsService(), - }); - - expect(cache).toMatchObject(sampleIndexPatterns); - }); - - it('should allow scripted, but not full text fields', async () => { - const cache = await loadIndexPatterns({ - cache: {}, - patterns: ['1', '2'], - indexPatternsService: mockIndexPatternsService(), - }); - - expect(cache).toMatchObject(sampleIndexPatterns); - }); - - it('should apply field restrictions from typeMeta', async () => { - const cache = await loadIndexPatterns({ - cache: {}, - patterns: ['foo'], - indexPatternsService: { - get: jest.fn(async () => ({ - id: 'foo', - title: 'Foo index', - metaFields: [], - typeMeta: { - aggs: { - date_histogram: { - timestamp: { - agg: 'date_histogram', - fixed_interval: 'm', - }, - }, - sum: { - bytes: { - agg: 'sum', - }, - }, - }, - }, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - })), - getIdsWithTitle: jest.fn(async () => ({ - id: 'foo', - title: 'Foo index', - })), - } as unknown as Pick, - }); - - expect(cache.foo.getFieldByName('bytes')!.aggregationRestrictions).toEqual({ - sum: { agg: 'sum' }, - }); - expect(cache.foo.getFieldByName('timestamp')!.aggregationRestrictions).toEqual({ - date_histogram: { agg: 'date_histogram', fixed_interval: 'm' }, - }); - }); - - it('should map meta flag', async () => { - const cache = await loadIndexPatterns({ - cache: {}, - patterns: ['foo'], - indexPatternsService: { - get: jest.fn(async () => ({ - id: 'foo', - title: 'Foo index', - metaFields: ['timestamp'], - typeMeta: { - aggs: { - date_histogram: { - timestamp: { - agg: 'date_histogram', - fixed_interval: 'm', - }, - }, - sum: { - bytes: { - agg: 'sum', - }, - }, - }, - }, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], - })), - getIdsWithTitle: jest.fn(async () => ({ - id: 'foo', - title: 'Foo index', - })), - } as unknown as Pick, - }); - - expect(cache.foo.getFieldByName('timestamp')!.meta).toEqual(true); - }); - }); - describe('loadInitialState', () => { - it('should load a default state', async () => { + it('should load a default state', () => { const storage = createMockStorage(); - const state = await loadInitialState({ - indexPatternsService: mockIndexPatternsService(), + const state = loadInitialState({ + indexPatterns: sampleIndexPatterns, + indexPatternRefs, storage, - options: { isFullEditor: true }, }); expect(state).toMatchObject({ currentIndexPatternId: '1', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, layers: {}, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { @@ -391,43 +55,32 @@ describe('loader', () => { }); }); - it('should load a default state without loading the indexPatterns when embedded', async () => { + it('should load a default state without loading the indexPatterns when embedded', () => { const storage = createMockStorage(); - const indexPatternsService = mockIndexPatternsService(); - const state = await loadInitialState({ - indexPatternsService, + const state = loadInitialState({ storage, - options: { isFullEditor: false }, + indexPatterns: {}, + indexPatternRefs: [], }); expect(state).toMatchObject({ currentIndexPatternId: undefined, - indexPatternRefs: [], - indexPatterns: {}, layers: {}, }); expect(storage.set).not.toHaveBeenCalled(); - expect(indexPatternsService.getIdsWithTitle).not.toHaveBeenCalled(); }); - it('should load a default state when lastUsedIndexPatternId is not found in indexPatternRefs', async () => { + it('should load a default state when lastUsedIndexPatternId is not found in indexPatternRefs', () => { const storage = createMockStorage({ indexPatternId: 'c' }); - const state = await loadInitialState({ - indexPatternsService: mockIndexPatternsService(), + const state = loadInitialState({ storage, - options: { isFullEditor: true }, + indexPatternRefs, + indexPatterns: sampleIndexPatterns, }); expect(state).toMatchObject({ currentIndexPatternId: '1', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, layers: {}, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { @@ -435,44 +88,30 @@ describe('loader', () => { }); }); - it('should load lastUsedIndexPatternId if in localStorage', async () => { - const state = await loadInitialState({ - indexPatternsService: mockIndexPatternsService(), + it('should load lastUsedIndexPatternId if in localStorage', () => { + const state = loadInitialState({ storage: createMockStorage({ indexPatternId: '2' }), - options: { isFullEditor: true }, + indexPatternRefs, + indexPatterns: sampleIndexPatterns, }); expect(state).toMatchObject({ currentIndexPatternId: '2', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '2': sampleIndexPatterns['2'], - }, layers: {}, }); }); - it('should use the default index pattern id, if provided', async () => { + it('should use the default index pattern id, if provided', () => { const storage = createMockStorage(); - const state = await loadInitialState({ + const state = loadInitialState({ defaultIndexPatternId: '2', - indexPatternsService: mockIndexPatternsService(), storage, - options: { isFullEditor: true }, + indexPatternRefs, + indexPatterns: sampleIndexPatterns, }); expect(state).toMatchObject({ currentIndexPatternId: '2', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '2': sampleIndexPatterns['2'], - }, layers: {}, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { @@ -480,27 +119,20 @@ describe('loader', () => { }); }); - it('should use the indexPatternId of the visualize trigger field, if provided', async () => { + it('should use the indexPatternId of the visualize trigger field, if provided', () => { const storage = createMockStorage(); - const state = await loadInitialState({ - indexPatternsService: mockIndexPatternsService(), + const state = loadInitialState({ storage, initialContext: { indexPatternId: '1', fieldName: '', }, - options: { isFullEditor: true }, + indexPatternRefs, + indexPatterns: sampleIndexPatterns, }); expect(state).toMatchObject({ currentIndexPatternId: '1', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, layers: {}, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { @@ -508,10 +140,9 @@ describe('loader', () => { }); }); - it('should use the indexPatternId of the visualize trigger chart context, if provided', async () => { + it('should use the indexPatternId of the visualize trigger chart context, if provided', () => { const storage = createMockStorage(); - const state = await loadInitialState({ - indexPatternsService: mockIndexPatternsService(), + const state = loadInitialState({ storage, initialContext: { layers: [ @@ -541,18 +172,12 @@ describe('loader', () => { savedObjectId: '', isVisualizeAction: true, }, - options: { isFullEditor: true }, + indexPatternRefs, + indexPatterns: sampleIndexPatterns, }); expect(state).toMatchObject({ currentIndexPatternId: '1', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, layers: {}, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { @@ -560,7 +185,7 @@ describe('loader', () => { }); }); - it('should initialize all the embeddable references without local storage', async () => { + it('should initialize all the embeddable references without local storage', () => { const savedState: IndexPatternPersistedState = { layers: { layerb: { @@ -588,29 +213,27 @@ describe('loader', () => { }, }; const storage = createMockStorage({}); - const state = await loadInitialState({ + const state = loadInitialState({ persistedState: savedState, references: [ { name: 'indexpattern-datasource-layer-layerb', id: '2', type: 'index-pattern' }, { name: 'another-reference', id: 'c', type: 'index-pattern' }, ], - indexPatternsService: mockIndexPatternsService(), + indexPatternRefs: [], + indexPatterns: { + '2': sampleIndexPatterns['2'], + }, storage, - options: { isFullEditor: false }, }); expect(state).toMatchObject({ currentIndexPatternId: undefined, - indexPatternRefs: [], - indexPatterns: { - '2': sampleIndexPatterns['2'], - }, layers: { layerb: { ...savedState.layers.layerb, indexPatternId: '2' } }, }); expect(storage.set).not.toHaveBeenCalled(); }); - it('should initialize from saved state', async () => { + it('should initialize from saved state', () => { const savedState: IndexPatternPersistedState = { layers: { layerb: { @@ -638,117 +261,27 @@ describe('loader', () => { }, }; const storage = createMockStorage({ indexPatternId: '1' }); - const state = await loadInitialState({ + const state = loadInitialState({ persistedState: savedState, references: [ { name: 'indexpattern-datasource-layer-layerb', id: '2', type: 'index-pattern' }, { name: 'another-reference', id: 'c', type: 'index-pattern' }, ], - indexPatternsService: mockIndexPatternsService(), - storage, - options: { isFullEditor: true }, - }); - expect(state).toMatchObject({ - currentIndexPatternId: '2', - indexPatternRefs: [ - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], + indexPatternRefs, indexPatterns: { '2': sampleIndexPatterns['2'], }, - layers: { layerb: { ...savedState.layers.layerb, indexPatternId: '2' } }, - }); - - expect(storage.set).toHaveBeenCalledWith('lens-settings', { - indexPatternId: '2', - }); - }); - - it('should default to the first loaded index pattern if could not load any used one or one from the storage', async () => { - function mockIndexPatternsServiceWithConflict() { - return { - get: jest.fn(async (id: '1' | '2' | 'conflictId') => { - if (id === 'conflictId') { - return Promise.reject(new Error('Oh noes conflict boom')); - } - const result = { ...sampleIndexPatternsFromService[id], metaFields: [] }; - if (!result.fields) { - result.fields = []; - } - return result; - }), - getIdsWithTitle: jest.fn(async () => { - return [ - { - id: sampleIndexPatterns[1].id, - title: sampleIndexPatterns[1].title, - }, - { - id: sampleIndexPatterns[2].id, - title: sampleIndexPatterns[2].title, - }, - { - id: 'conflictId', - title: 'conflictId title', - }, - ]; - }), - } as unknown as Pick; - } - const savedState: IndexPatternPersistedState = { - layers: { - layerb: { - columnOrder: ['col1', 'col2'], - columns: { - col1: { - dataType: 'date', - isBucketed: true, - label: 'My date', - operationType: 'date_histogram', - params: { - interval: 'm', - }, - sourceField: 'timestamp', - } as DateHistogramIndexPatternColumn, - col2: { - dataType: 'number', - isBucketed: false, - label: 'Sum of bytes', - operationType: 'sum', - sourceField: 'bytes', - }, - }, - }, - }, - }; - const storage = createMockStorage({ indexPatternId: 'conflictId' }); - const state = await loadInitialState({ - persistedState: savedState, - references: [ - { name: 'indexpattern-datasource-layer-layerb', id: 'conflictId', type: 'index-pattern' }, - ], - indexPatternsService: mockIndexPatternsServiceWithConflict(), storage, - options: { isFullEditor: true }, }); expect(state).toMatchObject({ - currentIndexPatternId: '1', - indexPatternRefs: [ - { id: 'conflictId', title: 'conflictId title' }, - { id: '1', title: sampleIndexPatterns['1'].title }, - { id: '2', title: sampleIndexPatterns['2'].title }, - ], - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, - layers: { layerb: { ...savedState.layers.layerb, indexPatternId: 'conflictId' } }, + currentIndexPatternId: '2', + layers: { layerb: { ...savedState.layers.layerb, indexPatternId: '2' } }, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { - indexPatternId: '1', + indexPatternId: '2', }); }); }); @@ -756,9 +289,6 @@ describe('loader', () => { describe('saved object references', () => { const state: IndexPatternPrivateState = { currentIndexPatternId: 'b', - indexPatternRefs: [], - indexPatterns: {}, - existingFields: {}, layers: { a: { indexPatternId: 'id-index-pattern-a', @@ -787,7 +317,6 @@ describe('loader', () => { }, }, }, - isFirstExistenceFetch: false, }; it('should create a reference for each layer and for current index pattern', () => { @@ -815,95 +344,111 @@ describe('loader', () => { }); describe('changeIndexPattern', () => { - it('loads the index pattern and then sets it as current', async () => { - const setState = jest.fn(); + it('sets the given indexpattern as current', () => { const state: IndexPatternPrivateState = { currentIndexPatternId: '2', - indexPatternRefs: [], - indexPatterns: {}, - existingFields: {}, layers: {}, - isFirstExistenceFetch: false, }; const storage = createMockStorage({ indexPatternId: '2' }); - await changeIndexPattern({ + const newState = changeIndexPattern({ + indexPatternId: '1', state, - setState, - id: '1', - indexPatternsService: mockIndexPatternsService(), - onError: jest.fn(), storage, + indexPatterns: { + '1': sampleIndexPatterns['1'], + }, }); - expect(setState).toHaveBeenCalledTimes(1); - const [fn, options] = setState.mock.calls[0]; - expect(options).toEqual({ applyImmediately: true }); - expect(fn(state)).toMatchObject({ + expect(newState).toMatchObject({ currentIndexPatternId: '1', - indexPatterns: { - '1': { - ...sampleIndexPatterns['1'], - fields: [...sampleIndexPatterns['1'].fields], - }, - }, }); expect(storage.set).toHaveBeenCalledWith('lens-settings', { indexPatternId: '1', }); }); - it('handles errors', async () => { - const setState = jest.fn(); - const onError = jest.fn(); - const err = new Error('NOPE!'); + it('should update an empty layer on indexpattern change', () => { const state: IndexPatternPrivateState = { currentIndexPatternId: '2', - indexPatternRefs: [], - existingFields: {}, - indexPatterns: {}, - layers: {}, - isFirstExistenceFetch: false, + layers: { layerId: { columnOrder: [], columns: {}, indexPatternId: '2' } }, }; - const storage = createMockStorage({ indexPatternId: '2' }); - await changeIndexPattern({ + const newState = changeIndexPattern({ + indexPatternId: '1', state, - setState, - id: '1', - indexPatternsService: { - get: jest.fn(async () => { - throw err; - }), - getIdsWithTitle: jest.fn(), - }, - onError, storage, + indexPatterns: sampleIndexPatterns, }); - expect(setState).not.toHaveBeenCalled(); - expect(storage.set).not.toHaveBeenCalled(); - expect(onError).toHaveBeenCalledWith(Error('Missing indexpatterns')); + expect(newState.layers.layerId).toEqual({ + columnOrder: [], + columns: {}, + indexPatternId: '1', + }); }); - }); - describe('changeLayerIndexPattern', () => { - let uiActions: UiActionsStart; + it('should keep layer indexpattern on change if not empty', () => { + const state: IndexPatternPrivateState = { + currentIndexPatternId: '2', + layers: { + layerId: { + columnOrder: ['col1'], + columns: { + col1: { + dataType: 'string', + isBucketed: true, + label: '', + operationType: 'terms', + sourceField: 'bytes', + params: { + orderBy: { type: 'alphabetical' }, + orderDirection: 'asc', + size: 3, + }, + } as TermsIndexPatternColumn, + }, + indexPatternId: '2', + }, + }, + }; + const storage = createMockStorage({ indexPatternId: '2' }); + + const newState = changeIndexPattern({ + indexPatternId: '1', + state, + storage, + indexPatterns: sampleIndexPatterns, + }); - beforeEach(() => { - uiActions = uiActionsPluginMock.createStartContract(); + expect(newState.layers).toEqual({ + layerId: { + columnOrder: ['col1'], + columns: { + col1: { + dataType: 'string', + isBucketed: true, + label: '', + operationType: 'terms', + sourceField: 'bytes', + params: { + orderBy: { type: 'alphabetical' }, + orderDirection: 'asc', + size: 3, + }, + }, + }, + indexPatternId: '2', + }, + }); }); + }); + describe('changeLayerIndexPattern', () => { it('loads the index pattern and then changes the specified layer', async () => { - const setState = jest.fn(); const state: IndexPatternPrivateState = { - currentIndexPatternId: '2', - indexPatternRefs: [], - existingFields: {}, - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, + currentIndexPatternId: '1', layers: { l0: { columnOrder: ['col1'], @@ -927,29 +472,21 @@ describe('loader', () => { indexPatternId: '1', }, }, - isFirstExistenceFetch: false, }; const storage = createMockStorage({ indexPatternId: '1' }); - await changeLayerIndexPattern({ + const newState = changeLayerIndexPattern({ state, - setState, indexPatternId: '2', layerId: 'l1', - indexPatternsService: mockIndexPatternsService(), - onError: jest.fn(), storage, - uiActions, + indexPatterns: sampleIndexPatterns, + replaceIfPossible: true, }); - expect(setState).toHaveBeenCalledTimes(1); - expect(setState.mock.calls[0][0](state)).toMatchObject({ + expect(newState).toMatchObject({ currentIndexPatternId: '2', - indexPatterns: { - 1: sampleIndexPatterns['1'], - 2: sampleIndexPatterns['2'], - }, layers: { l0: { columnOrder: ['col1'], @@ -978,239 +515,5 @@ describe('loader', () => { indexPatternId: '2', }); }); - - it('handles errors', async () => { - const setState = jest.fn(); - const onError = jest.fn(); - const err = new Error('NOPE!'); - const state: IndexPatternPrivateState = { - currentIndexPatternId: '2', - indexPatternRefs: [], - existingFields: {}, - indexPatterns: { - '1': sampleIndexPatterns['1'], - }, - layers: { - l0: { - columnOrder: ['col1'], - columns: {}, - indexPatternId: '1', - }, - }, - isFirstExistenceFetch: false, - }; - - const storage = createMockStorage({ indexPatternId: '2' }); - - await changeLayerIndexPattern({ - state, - setState, - indexPatternId: '2', - layerId: 'l0', - indexPatternsService: { - get: jest.fn(async () => { - throw err; - }), - getIdsWithTitle: jest.fn(), - }, - onError, - storage, - uiActions, - }); - - expect(setState).not.toHaveBeenCalled(); - expect(storage.set).not.toHaveBeenCalled(); - expect(onError).toHaveBeenCalledWith(Error('Missing indexpatterns')); - }); - }); - - describe('syncExistingFields', () => { - const dslQuery = { - bool: { - must: [], - filter: [{ match_all: {} }], - should: [], - must_not: [], - }, - }; - - it('should call once for each index pattern', async () => { - const setState = jest.fn(); - const fetchJson = jest.fn((path: string) => { - const indexPatternTitle = last(path.split('/')); - return { - indexPatternTitle, - existingFieldNames: ['field_1', 'field_2'].map( - (fieldName) => `ip${indexPatternTitle}_${fieldName}` - ), - }; - }) as unknown as HttpHandler; - - await syncExistingFields({ - dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, - indexPatterns: [ - { id: '1', title: '1', fields: [], hasRestrictions: false }, - { id: '2', title: '1', fields: [], hasRestrictions: false }, - { id: '3', title: '1', fields: [], hasRestrictions: false }, - ], - setState, - dslQuery, - showNoDataPopover: jest.fn(), - currentIndexPatternTitle: 'abc', - isFirstExistenceFetch: false, - }); - - expect(fetchJson).toHaveBeenCalledTimes(3); - expect(setState).toHaveBeenCalledTimes(1); - - const [fn, options] = setState.mock.calls[0]; - expect(options).toEqual({ applyImmediately: true }); - const newState = fn({ - foo: 'bar', - existingFields: {}, - }); - - expect(newState).toEqual({ - foo: 'bar', - isFirstExistenceFetch: false, - existenceFetchFailed: false, - existenceFetchTimeout: false, - existingFields: { - '1': { ip1_field_1: true, ip1_field_2: true }, - '2': { ip2_field_1: true, ip2_field_2: true }, - '3': { ip3_field_1: true, ip3_field_2: true }, - }, - }); - }); - - it('should call showNoDataPopover callback if current index pattern returns no fields', async () => { - const setState = jest.fn(); - const showNoDataPopover = jest.fn(); - const fetchJson = jest.fn((path: string) => { - const indexPatternTitle = last(path.split('/')); - return { - indexPatternTitle, - existingFieldNames: - indexPatternTitle === '1' - ? ['field_1', 'field_2'].map((fieldName) => `${indexPatternTitle}_${fieldName}`) - : [], - }; - }) as unknown as HttpHandler; - - const args = { - dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, - indexPatterns: [ - { id: '1', title: '1', fields: [], hasRestrictions: false }, - { id: '2', title: '1', fields: [], hasRestrictions: false }, - { id: 'c', title: '1', fields: [], hasRestrictions: false }, - ], - setState, - dslQuery, - showNoDataPopover: jest.fn(), - currentIndexPatternTitle: 'abc', - isFirstExistenceFetch: false, - }; - - await syncExistingFields(args); - - expect(showNoDataPopover).not.toHaveBeenCalled(); - - await syncExistingFields({ ...args, isFirstExistenceFetch: true }); - expect(showNoDataPopover).not.toHaveBeenCalled(); - }); - - it('should set all fields to available and existence error flag if the request fails', async () => { - const setState = jest.fn(); - const fetchJson = jest.fn((path: string) => { - return new Promise((resolve, reject) => { - reject(new Error()); - }); - }) as unknown as HttpHandler; - - const args = { - dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, - indexPatterns: [ - { - id: '1', - title: '1', - hasRestrictions: false, - fields: [{ name: 'field1' }, { name: 'field2' }] as IndexPatternField[], - }, - ], - setState, - dslQuery, - showNoDataPopover: jest.fn(), - currentIndexPatternTitle: 'abc', - isFirstExistenceFetch: false, - }; - - await syncExistingFields(args); - - const [fn, options] = setState.mock.calls[0]; - expect(options).toEqual({ applyImmediately: true }); - const newState = fn({ - foo: 'bar', - existingFields: {}, - }) as IndexPatternPrivateState; - - expect(newState.existenceFetchFailed).toEqual(true); - expect(newState.existenceFetchTimeout).toEqual(false); - expect(newState.existingFields['1']).toEqual({ - field1: true, - field2: true, - }); - }); - - it('should set all fields to available and existence error flag if the request times out', async () => { - const setState = jest.fn(); - const fetchJson = jest.fn((path: string) => { - return new Promise((resolve, reject) => { - const error = createHttpFetchError( - 'timeout', - 'error', - {} as Request, - { status: 408 } as Response - ); - reject(error); - }); - }) as unknown as HttpHandler; - - const args = { - dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, - fetchJson, - indexPatterns: [ - { - id: '1', - title: '1', - hasRestrictions: false, - fields: [{ name: 'field1' }, { name: 'field2' }] as IndexPatternField[], - }, - ], - setState, - dslQuery, - showNoDataPopover: jest.fn(), - currentIndexPatternTitle: 'abc', - isFirstExistenceFetch: false, - }; - - await syncExistingFields(args); - - const [fn, options] = setState.mock.calls[0]; - expect(options).toEqual({ applyImmediately: true }); - const newState = fn({ - foo: 'bar', - existingFields: {}, - }) as IndexPatternPrivateState; - - expect(newState.existenceFetchFailed).toEqual(false); - expect(newState.existenceFetchTimeout).toEqual(true); - expect(newState.existingFields['1']).toEqual({ - field1: true, - field2: true, - }); - }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index d3affb5b32d8c2..f7a6912390027c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -7,9 +7,7 @@ import { uniq, mapValues, difference } from 'lodash'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; -import type { HttpSetup, SavedObjectReference } from '@kbn/core/public'; -import type { DataViewsContract, DataView } from '@kbn/data-views-plugin/public'; -import { isNestedField } from '@kbn/data-views-plugin/common'; +import type { SavedObjectReference } from '@kbn/core/public'; import { UPDATE_FILTER_REFERENCES_ACTION, UPDATE_FILTER_REFERENCES_TRIGGER, @@ -19,148 +17,18 @@ import { UiActionsStart, VisualizeFieldContext, } from '@kbn/ui-actions-plugin/public'; -import type { - DatasourceDataPanelProps, - InitializationOptions, - VisualizeEditorContext, -} from '../types'; -import { - IndexPattern, - IndexPatternRef, - IndexPatternPersistedState, - IndexPatternPrivateState, - IndexPatternField, - IndexPatternLayer, -} from './types'; +import type { VisualizeEditorContext } from '../types'; +import { IndexPatternPersistedState, IndexPatternPrivateState, IndexPatternLayer } from './types'; -import { updateLayerIndexPattern, translateToOperationName } from './operations'; -import { DateRange, ExistingFields } from '../../common/types'; -import { BASE_API_URL } from '../../common'; -import { documentField } from './document_field'; +import { memoizedGetAvailableOperationsByMetadata, updateLayerIndexPattern } from './operations'; import { readFromStorage, writeToStorage } from '../settings_storage'; -import { getFieldByNameFactory } from './pure_helpers'; -import { memoizedGetAvailableOperationsByMetadata } from './operations'; - -type SetState = DatasourceDataPanelProps['setState']; -type IndexPatternsService = Pick; -type ErrorHandler = (err: Error) => void; - -export function convertDataViewIntoLensIndexPattern(dataView: DataView): IndexPattern { - const newFields = dataView.fields - .filter((field) => !isNestedField(field) && (!!field.aggregatable || !!field.scripted)) - .map((field): IndexPatternField => { - // Convert the getters on the index pattern service into plain JSON - const base = { - name: field.name, - displayName: field.displayName, - type: field.type, - aggregatable: field.aggregatable, - searchable: field.searchable, - meta: dataView.metaFields.includes(field.name), - esTypes: field.esTypes, - scripted: field.scripted, - runtime: Boolean(field.runtimeField), - }; - - // Simplifies tests by hiding optional properties instead of undefined - return base.scripted - ? { - ...base, - lang: field.lang, - script: field.script, - } - : base; - }) - .concat(documentField); - - const { typeMeta, title, name, timeFieldName, fieldFormatMap } = dataView; - if (typeMeta?.aggs) { - const aggs = Object.keys(typeMeta.aggs); - newFields.forEach((field, index) => { - const restrictionsObj: IndexPatternField['aggregationRestrictions'] = {}; - aggs.forEach((agg) => { - const restriction = typeMeta.aggs && typeMeta.aggs[agg] && typeMeta.aggs[agg][field.name]; - if (restriction) { - restrictionsObj[translateToOperationName(agg)] = restriction; - } - }); - if (Object.keys(restrictionsObj).length) { - newFields[index] = { ...field, aggregationRestrictions: restrictionsObj }; - } - }); - } - - return { - id: dataView.id!, // id exists for sure because we got index patterns by id - title, - name: name ? name : title, - timeFieldName, - fieldFormatMap: - fieldFormatMap && - Object.fromEntries( - Object.entries(fieldFormatMap).map(([id, format]) => [ - id, - // @ts-expect-error FIXME Property 'toJSON' does not exist on type 'SerializedFieldFormat' - 'toJSON' in format ? format.toJSON() : format, - ]) - ), - fields: newFields, - getFieldByName: getFieldByNameFactory(newFields, false), - hasRestrictions: !!typeMeta?.aggs, - }; -} - -export async function loadIndexPatterns({ - indexPatternsService, - patterns, - notUsedPatterns, - cache, -}: { - indexPatternsService: IndexPatternsService; - patterns: string[]; - notUsedPatterns?: string[]; - cache: Record; -}) { - const missingIds = patterns.filter((id) => !cache[id]); - - if (missingIds.length === 0) { - return cache; - } +import type { IndexPattern, IndexPatternRef } from '../types'; +export function onRefreshIndexPattern() { if (memoizedGetAvailableOperationsByMetadata.cache.clear) { // clear operations meta data cache because index pattern reference may change memoizedGetAvailableOperationsByMetadata.cache.clear(); } - - const allIndexPatterns = await Promise.allSettled( - missingIds.map((id) => indexPatternsService.get(id)) - ); - // ignore rejected indexpatterns here, they're already handled at the app level - let indexPatterns = allIndexPatterns - .filter( - (response): response is PromiseFulfilledResult => response.status === 'fulfilled' - ) - .map((response) => response.value); - - // if all of the used index patterns failed to load, try loading one of not used ones till one succeeds - for (let i = 0; notUsedPatterns && i < notUsedPatterns?.length && !indexPatterns.length; i++) { - const resp = await indexPatternsService.get(notUsedPatterns[i]).catch((e) => { - // do nothing - }); - if (resp) { - indexPatterns = [resp]; - } - } - - const indexPatternsObject = indexPatterns.reduce( - (acc, indexPattern) => ({ - [indexPattern.id!]: convertDataViewIntoLensIndexPattern(indexPattern), - ...acc, - }), - { ...cache } - ); - - return indexPatternsObject; } const getLastUsedIndexPatternId = ( @@ -209,42 +77,43 @@ export function injectReferences( }; } -export async function loadInitialState({ +function createStateFromPersisted({ persistedState, references, - defaultIndexPatternId, - storage, - indexPatternsService, - initialContext, - options, }: { persistedState?: IndexPatternPersistedState; references?: SavedObjectReference[]; +}) { + return persistedState && references ? injectReferences(persistedState, references) : undefined; +} + +function getUsedIndexPatterns({ + state, + indexPatternRefs, + storage, + initialContext, + defaultIndexPatternId, +}: { + state?: { + layers: Record; + }; defaultIndexPatternId?: string; storage: IStorageWrapper; - indexPatternsService: IndexPatternsService; initialContext?: VisualizeFieldContext | VisualizeEditorContext; - options?: InitializationOptions; -}): Promise { - const { isFullEditor } = options ?? {}; - // make it explicit or TS will infer never[] and break few lines down - const indexPatternRefs: IndexPatternRef[] = await (isFullEditor - ? loadIndexPatternRefs(indexPatternsService) - : []); - + indexPatternRefs: IndexPatternRef[]; +}) { const lastUsedIndexPatternId = getLastUsedIndexPatternId(storage, indexPatternRefs); const fallbackId = lastUsedIndexPatternId || defaultIndexPatternId || indexPatternRefs[0]?.id; const indexPatternIds = []; - if (initialContext && 'isVisualizeAction' in initialContext) { - for (let layerIdx = 0; layerIdx < initialContext.layers.length; layerIdx++) { - const layerContext = initialContext.layers[layerIdx]; - indexPatternIds.push(layerContext.indexPatternId); + if (initialContext) { + if ('isVisualizeAction' in initialContext) { + for (const { indexPatternId } of initialContext.layers) { + indexPatternIds.push(indexPatternId); + } + } else { + indexPatternIds.push(initialContext.indexPatternId); } - } else if (initialContext) { - indexPatternIds.push(initialContext.indexPatternId); } - const state = - persistedState && references ? injectReferences(persistedState, references) : undefined; const usedPatterns = ( initialContext ? indexPatternIds @@ -253,30 +122,50 @@ export async function loadInitialState({ // take out the undefined from the list .filter(Boolean); - const notUsedPatterns: string[] = difference( - uniq(indexPatternRefs.map(({ id }) => id)), - usedPatterns - ); + return { + usedPatterns, + allIndexPatternIds: indexPatternIds, + }; +} + +export function loadInitialState({ + persistedState, + references, + defaultIndexPatternId, + storage, + initialContext, + indexPatternRefs = [], + indexPatterns = {}, +}: { + persistedState?: IndexPatternPersistedState; + references?: SavedObjectReference[]; + defaultIndexPatternId?: string; + storage: IStorageWrapper; + initialContext?: VisualizeFieldContext | VisualizeEditorContext; + indexPatternRefs?: IndexPatternRef[]; + indexPatterns?: Record; +}): IndexPatternPrivateState { + const state = createStateFromPersisted({ persistedState, references }); + const { usedPatterns, allIndexPatternIds: indexPatternIds } = getUsedIndexPatterns({ + state, + defaultIndexPatternId, + storage, + initialContext, + indexPatternRefs, + }); const availableIndexPatterns = new Set(indexPatternRefs.map(({ id }: IndexPatternRef) => id)); - const indexPatterns = await loadIndexPatterns({ - indexPatternsService, - cache: {}, - patterns: usedPatterns, - notUsedPatterns, - }); + const notUsedPatterns: string[] = difference([...availableIndexPatterns], usedPatterns); // Priority list: // * start with the indexPattern in context // * then fallback to the used ones // * then as last resort use a first one from not used refs - const availableIndexPatternIds = [...indexPatternIds, ...usedPatterns, ...notUsedPatterns].filter( + const currentIndexPatternId = [...indexPatternIds, ...usedPatterns, ...notUsedPatterns].find( (id) => id != null && availableIndexPatterns.has(id) && indexPatterns[id] ); - const currentIndexPatternId = availableIndexPatternIds[0]; - if (currentIndexPatternId) { setLastUsedIndexPatternId(storage, currentIndexPatternId); } @@ -285,78 +174,41 @@ export async function loadInitialState({ layers: {}, ...state, currentIndexPatternId, - indexPatternRefs, - indexPatterns, - existingFields: {}, - isFirstExistenceFetch: true, }; } -export async function changeIndexPattern({ - id, +export function changeIndexPattern({ + indexPatternId, state, - setState, - onError, storage, - indexPatternsService, + indexPatterns, }: { - id: string; + indexPatternId: string; state: IndexPatternPrivateState; - setState: SetState; - onError: ErrorHandler; storage: IStorageWrapper; - indexPatternsService: IndexPatternsService; + indexPatterns: Record; }) { - const indexPatterns = await loadIndexPatterns({ - indexPatternsService, - cache: state.indexPatterns, - patterns: [id], - }); - - if (indexPatterns[id] == null) { - return onError(Error('Missing indexpatterns')); - } - - try { - setState( - (s) => ({ - ...s, - layers: isSingleEmptyLayer(state.layers) - ? mapValues(state.layers, (layer) => updateLayerIndexPattern(layer, indexPatterns[id])) - : state.layers, - indexPatterns: { - ...s.indexPatterns, - [id]: indexPatterns[id], - }, - currentIndexPatternId: id, - }), - { applyImmediately: true } - ); - setLastUsedIndexPatternId(storage, id); - } catch (err) { - onError(err); - } + setLastUsedIndexPatternId(storage, indexPatternId); + return { + ...state, + layers: isSingleEmptyLayer(state.layers) + ? mapValues(state.layers, (layer) => + updateLayerIndexPattern(layer, indexPatterns[indexPatternId]) + ) + : state.layers, + currentIndexPatternId: indexPatternId, + }; } -export async function changeLayerIndexPattern({ - indexPatternId, - layerId, +export function triggerActionOnIndexPatternChange({ state, - setState, - onError, - replaceIfPossible, - storage, - indexPatternsService, + layerId, uiActions, + indexPatternId, }: { indexPatternId: string; layerId: string; state: IndexPatternPrivateState; - setState: SetState; - onError: ErrorHandler; - replaceIfPossible?: boolean; - storage: IStorageWrapper; - indexPatternsService: IndexPatternsService; uiActions: UiActionsStart; }) { const fromDataView = state.layers[layerId].indexPatternId; @@ -372,144 +224,32 @@ export async function changeLayerIndexPattern({ defaultDataView: toDataView, usedDataViews: Object.values(Object.values(state.layers).map((layer) => layer.indexPatternId)), } as ActionExecutionContext); - - const indexPatterns = await loadIndexPatterns({ - indexPatternsService, - cache: state.indexPatterns, - patterns: [indexPatternId], - }); - if (indexPatterns[indexPatternId] == null) { - return onError(Error('Missing indexpatterns')); - } - - try { - setState((s) => ({ - ...s, - layers: { - ...s.layers, - [layerId]: updateLayerIndexPattern(s.layers[layerId], indexPatterns[indexPatternId]), - }, - indexPatterns: { - ...s.indexPatterns, - [indexPatternId]: indexPatterns[indexPatternId], - }, - currentIndexPatternId: replaceIfPossible ? indexPatternId : s.currentIndexPatternId, - })); - setLastUsedIndexPatternId(storage, indexPatternId); - } catch (err) { - onError(err); - } -} - -async function loadIndexPatternRefs( - indexPatternsService: IndexPatternsService -): Promise { - const indexPatterns = await indexPatternsService.getIdsWithTitle(); - - return indexPatterns.sort((a, b) => { - return a.title.localeCompare(b.title); - }); } -export async function syncExistingFields({ +export function changeLayerIndexPattern({ + indexPatternId, indexPatterns, - dateRange, - fetchJson, - setState, - isFirstExistenceFetch, - currentIndexPatternTitle, - dslQuery, - showNoDataPopover, + layerId, + state, + replaceIfPossible, + storage, }: { - dateRange: DateRange; - indexPatterns: Array<{ - id: string; - title: string; - fields: IndexPatternField[]; - timeFieldName?: string | null; - hasRestrictions: boolean; - }>; - fetchJson: HttpSetup['post']; - setState: SetState; - isFirstExistenceFetch: boolean; - currentIndexPatternTitle: string; - dslQuery: object; - showNoDataPopover: () => void; + indexPatternId: string; + layerId: string; + state: IndexPatternPrivateState; + replaceIfPossible?: boolean; + storage: IStorageWrapper; + indexPatterns: Record; }) { - const existenceRequests = indexPatterns.map((pattern) => { - if (pattern.hasRestrictions) { - return { - indexPatternTitle: pattern.title, - existingFieldNames: pattern.fields.map((field) => field.name), - }; - } - const body: Record = { - dslQuery, - fromDate: dateRange.fromDate, - toDate: dateRange.toDate, - }; - - if (pattern.timeFieldName) { - body.timeFieldName = pattern.timeFieldName; - } - - return fetchJson(`${BASE_API_URL}/existing_fields/${pattern.id}`, { - body: JSON.stringify(body), - }) as Promise; - }); - - try { - const emptinessInfo = await Promise.all(existenceRequests); - if (isFirstExistenceFetch) { - const fieldsCurrentIndexPattern = emptinessInfo.find( - (info) => info.indexPatternTitle === currentIndexPatternTitle - ); - if (fieldsCurrentIndexPattern && fieldsCurrentIndexPattern.existingFieldNames.length === 0) { - showNoDataPopover(); - } - } - - setState( - (state) => ({ - ...state, - isFirstExistenceFetch: false, - existenceFetchFailed: false, - existenceFetchTimeout: false, - existingFields: emptinessInfo.reduce( - (acc, info) => { - acc[info.indexPatternTitle] = booleanMap(info.existingFieldNames); - return acc; - }, - { ...state.existingFields } - ), - }), - { applyImmediately: true } - ); - } catch (e) { - // show all fields as available if fetch failed or timed out - setState( - (state) => ({ - ...state, - existenceFetchFailed: e.res?.status !== 408, - existenceFetchTimeout: e.res?.status === 408, - existingFields: indexPatterns.reduce( - (acc, pattern) => { - acc[pattern.title] = booleanMap(pattern.fields.map((field) => field.name)); - return acc; - }, - { ...state.existingFields } - ), - }), - { applyImmediately: true } - ); - } -} - -function booleanMap(keys: string[]) { - return keys.reduce((acc, key) => { - acc[key] = true; - return acc; - }, {} as Record); + setLastUsedIndexPatternId(storage, indexPatternId); + return { + ...state, + layers: { + ...state.layers, + [layerId]: updateLayerIndexPattern(state.layers[layerId], indexPatterns[indexPatternId]), + }, + currentIndexPatternId: replaceIfPossible ? indexPatternId : state.currentIndexPatternId, + }; } function isSingleEmptyLayer(layerMap: IndexPatternPrivateState['layers']) { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 079a866676f04e..d76e6723c1be9e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -7,7 +7,7 @@ import { DragContextState } from '../drag_drop'; import { getFieldByNameFactory } from './pure_helpers'; -import type { IndexPattern, IndexPatternField } from './types'; +import type { IndexPattern, IndexPatternField } from '../types'; export const createMockedIndexPatternWithoutType = ( typeToFilter: IndexPatternField['type'] diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions.test.ts index c9b3d03a8b3610..6bcbbf40109a22 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions.test.ts @@ -18,7 +18,8 @@ import { } from './definitions'; import { getFieldByNameFactory } from '../pure_helpers'; import { documentField } from '../document_field'; -import { IndexPattern, IndexPatternLayer, IndexPatternField } from '../types'; +import { IndexPatternLayer } from '../types'; +import { IndexPattern, IndexPatternField } from '../../types'; import { GenericIndexPatternColumn } from '.'; import { DateHistogramIndexPatternColumn } from './definitions/date_histogram'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts index b9998e943c515f..04a8f554be7dfe 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts @@ -8,9 +8,10 @@ import { i18n } from '@kbn/i18n'; import type { AstFunction } from '@kbn/interpreter'; import memoizeOne from 'memoize-one'; +import type { IndexPattern } from '../../../../types'; import { LayerType, layerTypes } from '../../../../../common'; import type { TimeScaleUnit } from '../../../../../common/expressions'; -import type { IndexPattern, IndexPatternLayer } from '../../../types'; +import type { IndexPatternLayer } from '../../../types'; import { adjustTimeScaleLabelSuffix } from '../../time_scale_utils'; import type { ReferenceBasedIndexPatternColumn } from '../column_types'; import { getManagedColumnsFrom, isColumnValidAsReference } from '../../layer_helpers'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx index bf61755e79f4c4..a80e1f7e1c718d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx @@ -14,7 +14,7 @@ import { buildExpressionFunction } from '@kbn/expressions-plugin/public'; import { TimeScaleUnit } from '../../../../common/expressions'; import { OperationDefinition, ParamEditorProps } from '.'; import { FieldBasedIndexPatternColumn, ValueFormatConfig } from './column_types'; -import { IndexPatternField } from '../../types'; +import type { IndexPatternField } from '../../../types'; import { getInvalidFieldMessage, getFilter, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index 012bf86bf80401..4afbe7aa016c21 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -18,7 +18,8 @@ import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { UI_SETTINGS } from '@kbn/data-plugin/public'; import { dataPluginMock, getCalculateAutoTimeExpression } from '@kbn/data-plugin/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; -import type { IndexPatternLayer, IndexPattern } from '../../types'; +import type { IndexPatternLayer } from '../../types'; +import type { IndexPattern } from '../../../types'; import { getFieldByNameFactory } from '../../pure_helpers'; import { act } from 'react-dom/test-utils'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filter_popover.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filter_popover.tsx index 7166da0a3c0dfd..c4ab33c36f1f1e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filter_popover.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filter_popover.tsx @@ -10,8 +10,8 @@ import './filter_popover.scss'; import React from 'react'; import { EuiPopover, EuiSpacer } from '@elastic/eui'; import type { Query } from '@kbn/es-query'; +import { IndexPattern } from '../../../../types'; import { FilterValue, defaultLabel, isQueryValid } from '.'; -import { IndexPattern } from '../../../types'; import { LabelInput } from '../shared_components'; import { QueryInput } from '../../../query_input'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx index 3890494be8b464..cee188b6f483ab 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/filters/filters.tsx @@ -15,12 +15,12 @@ import type { Query } from '@kbn/es-query'; import type { AggFunctionsMapping } from '@kbn/data-plugin/public'; import { queryFilterToAst } from '@kbn/data-plugin/common'; import { buildExpressionFunction } from '@kbn/expressions-plugin/public'; +import { IndexPattern } from '../../../../types'; import { updateColumnParam } from '../../layer_helpers'; import type { OperationDefinition } from '..'; import type { BaseIndexPatternColumn } from '../column_types'; import { FilterPopover } from './filter_popover'; -import type { IndexPattern } from '../../../types'; -import { NewBucketButton, DragDropBuckets, DraggableBucketContainer } from '../shared_components'; +import { DragDropBuckets, DraggableBucketContainer, NewBucketButton } from '../shared_components'; const generateId = htmlIdGenerator(); const OPERATION_NAME = 'filters'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx index 7a6d4c051c2a22..75c65a204907ae 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx @@ -21,7 +21,7 @@ import { EuiSpacer, } from '@elastic/eui'; import { Markdown } from '@kbn/kibana-react-plugin/public'; -import { IndexPattern } from '../../../../types'; +import type { IndexPattern } from '../../../../../types'; import { tinymathFunctions } from '../util'; import { getPossibleFunctions } from './math_completion'; import { hasFunctionFieldArgument } from '../validation'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.test.ts index 8a59636d099526..d90a021a7cb12d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.test.ts @@ -11,8 +11,7 @@ import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { createMockedIndexPattern } from '../../../../mocks'; import { GenericOperationDefinition } from '../..'; -import type { IndexPatternField } from '../../../../types'; -import type { OperationMetadata } from '../../../../../types'; +import type { OperationMetadata, IndexPatternField } from '../../../../../types'; import { tinymathFunctions } from '../util'; import { getSignatureHelp, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts index 9e30eadee6aa61..eab7d03a17ae59 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts @@ -22,7 +22,7 @@ import type { } from '@kbn/unified-search-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { parseTimeShift } from '@kbn/data-plugin/common'; -import { IndexPattern } from '../../../../types'; +import type { IndexPattern } from '../../../../../types'; import { memoizedGetAvailableOperationsByMetadata } from '../../../operations'; import { tinymathFunctions, groupArgsByType, unquotedStringRegex } from '../util'; import type { GenericOperationDefinition } from '../..'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx index 1e16c27253d9b9..e68bb0d3142ef6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.test.tsx @@ -9,7 +9,8 @@ import { createMockedIndexPattern } from '../../../mocks'; import { formulaOperation, GenericOperationDefinition, GenericIndexPatternColumn } from '..'; import { FormulaIndexPatternColumn } from './formula'; import { insertOrReplaceFormulaColumn } from './parse'; -import type { IndexPattern, IndexPatternField, IndexPatternLayer } from '../../../types'; +import type { IndexPatternLayer } from '../../../types'; +import { IndexPattern, IndexPatternField } from '../../../../types'; import { tinymathFunctions } from './util'; import { TermsIndexPatternColumn } from '../terms'; import { MovingAverageIndexPatternColumn } from '../calculations'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx index 72aace21479acf..c3562fb649665d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import type { BaseIndexPatternColumn, OperationDefinition } from '..'; import type { ReferenceBasedIndexPatternColumn } from '../column_types'; -import type { IndexPattern } from '../../../types'; +import type { IndexPattern } from '../../../../types'; import { runASTValidation, tryToParse } from './validation'; import { WrappedFormulaEditor } from './editor'; import { insertOrReplaceFormulaColumn } from './parse'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.test.ts index d1ee2023e1d1c9..3286696308d51d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.test.ts @@ -5,18 +5,18 @@ * 2.0. */ -import { convertDataViewIntoLensIndexPattern } from '../../../loader'; import { insertOrReplaceFormulaColumn } from './parse'; import { createFormulaPublicApi, FormulaPublicApi } from './formula_public_api'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DateHistogramIndexPatternColumn, PersistedIndexPatternLayer } from '../../../types'; +import { convertDataViewIntoLensIndexPattern } from '../../../../indexpattern_service/loader'; jest.mock('./parse', () => ({ insertOrReplaceFormulaColumn: jest.fn().mockReturnValue({}), })); -jest.mock('../../../loader', () => ({ +jest.mock('../../../../indexpattern_service/loader', () => ({ convertDataViewIntoLensIndexPattern: jest.fn((v) => v), })); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.ts index 8f431afa129e07..f5080de84d67d7 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula_public_api.ts @@ -6,10 +6,11 @@ */ import type { DataView } from '@kbn/data-views-plugin/public'; -import type { IndexPattern, PersistedIndexPatternLayer } from '../../../types'; +import { convertDataViewIntoLensIndexPattern } from '../../../../indexpattern_service/loader'; +import type { IndexPattern } from '../../../../types'; +import type { PersistedIndexPatternLayer } from '../../../types'; import { insertOrReplaceFormulaColumn } from './parse'; -import { convertDataViewIntoLensIndexPattern } from '../../../loader'; /** @public **/ export interface FormulaPublicApi { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx index d7f25275f63a27..b05c9f7c0fd218 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx @@ -8,7 +8,7 @@ import type { TinymathAST } from '@kbn/tinymath'; import { OperationDefinition } from '..'; import { ValueFormatConfig, ReferenceBasedIndexPatternColumn } from '../column_types'; -import { IndexPattern } from '../../../types'; +import { IndexPattern } from '../../../../types'; export interface MathIndexPatternColumn extends ReferenceBasedIndexPatternColumn { operationType: 'math'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/parse.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/parse.ts index 63e0935a3425b2..5c9a277070936d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/parse.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/parse.ts @@ -8,13 +8,14 @@ import { i18n } from '@kbn/i18n'; import { isObject } from 'lodash'; import type { TinymathAST, TinymathVariable, TinymathLocation } from '@kbn/tinymath'; +import type { IndexPattern } from '../../../../types'; import { OperationDefinition, GenericOperationDefinition, GenericIndexPatternColumn, operationDefinitionMap, } from '..'; -import type { IndexPattern, IndexPatternLayer } from '../../../types'; +import type { IndexPatternLayer } from '../../../types'; import { mathOperation } from './math'; import { documentField } from '../../../document_field'; import { runASTValidation, shouldHaveFieldArgument, tryToParse } from './validation'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts index edb95ad8d633cd..d943b7fbbf8f5f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts @@ -27,7 +27,8 @@ import type { GenericIndexPatternColumn, GenericOperationDefinition, } from '..'; -import type { IndexPattern, IndexPatternLayer } from '../../../types'; +import type { IndexPatternLayer } from '../../../types'; +import type { IndexPattern } from '../../../../types'; import type { TinymathNodeTypes } from './types'; interface ValidationErrors { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx index 4ca172df112e58..868d5e2557e49f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/helpers.tsx @@ -6,13 +6,14 @@ */ import { i18n } from '@kbn/i18n'; +import type { IndexPattern, IndexPatternField } from '../../../types'; import { GenericIndexPatternColumn, operationDefinitionMap } from '.'; import { FieldBasedIndexPatternColumn, FormattedIndexPatternColumn, ReferenceBasedIndexPatternColumn, } from './column_types'; -import { IndexPattern, IndexPatternField, IndexPatternLayer } from '../../types'; +import type { IndexPatternLayer } from '../../types'; import { hasField } from '../../pure_utils'; export function getInvalidFieldMessage( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index 7c8c6d81f2ce09..9a5abf8b796330 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -49,19 +49,20 @@ import { countOperation } from './count'; import { mathOperation, formulaOperation } from './formula'; import { staticValueOperation } from './static_value'; import { lastValueOperation } from './last_value'; -import { FrameDatasourceAPI, OperationMetadata, ParamEditorCustomProps } from '../../../types'; +import { + FrameDatasourceAPI, + IndexPattern, + IndexPatternField, + OperationMetadata, + ParamEditorCustomProps, +} from '../../../types'; import type { BaseIndexPatternColumn, IncompleteColumn, GenericIndexPatternColumn, ReferenceBasedIndexPatternColumn, } from './column_types'; -import { - DataViewDragDropOperation, - IndexPattern, - IndexPatternField, - IndexPatternLayer, -} from '../../types'; +import { DataViewDragDropOperation, IndexPatternLayer } from '../../types'; import { DateRange, LayerType } from '../../../../common'; import { rangeOperation } from './ranges'; import { IndexPatternDimensionEditorProps, OperationSupportMatrix } from '../../dimension_panel'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx index 7daa808275c26f..df219c1e851be1 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.test.tsx @@ -17,7 +17,8 @@ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { LastValueIndexPatternColumn } from './last_value'; import { lastValueOperation } from '.'; -import type { IndexPattern, IndexPatternLayer } from '../../types'; +import type { IndexPatternLayer } from '../../types'; +import type { IndexPattern } from '../../../types'; import { TermsIndexPatternColumn } from './terms'; import { EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx index 52e827a54f7559..f9fbb80e649c64 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx @@ -20,7 +20,7 @@ import { AggFunctionsMapping } from '@kbn/data-plugin/public'; import { buildExpressionFunction } from '@kbn/expressions-plugin/public'; import { OperationDefinition } from '.'; import { FieldBasedIndexPatternColumn, ValueFormatConfig } from './column_types'; -import { IndexPatternField, IndexPattern } from '../../types'; +import type { IndexPatternField, IndexPattern } from '../../../types'; import { DataType } from '../../../types'; import { getFormatFromPreviousColumn, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx index f0ac24ae2e9a3d..f72342f79bfc6a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.test.tsx @@ -18,7 +18,7 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { percentileOperation } from '.'; -import { IndexPattern, IndexPatternLayer } from '../../types'; +import { IndexPatternLayer } from '../../types'; import { PercentileIndexPatternColumn } from './percentile'; import { TermsIndexPatternColumn } from './terms'; import { @@ -27,6 +27,7 @@ import { ExpressionAstExpressionBuilder, } from '@kbn/expressions-plugin/public'; import type { OriginalColumn } from '../../to_expression'; +import { IndexPattern } from '../../../types'; jest.mock('lodash', () => { const original = jest.requireActual('lodash'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile_ranks.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile_ranks.test.tsx index 9d42e34c6af71b..a0c69a7354849c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile_ranks.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile_ranks.test.tsx @@ -18,9 +18,10 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { percentileRanksOperation } from '.'; -import { IndexPattern, IndexPatternLayer } from '../../types'; +import { IndexPatternLayer } from '../../types'; import type { PercentileRanksIndexPatternColumn } from './percentile_ranks'; import { TermsIndexPatternColumn } from './terms'; +import { IndexPattern } from '../../../types'; jest.mock('lodash', () => { const original = jest.requireActual('lodash'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index 656e9e31459d32..43603d94154d49 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -15,7 +15,7 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; -import type { IndexPatternLayer, IndexPattern } from '../../../types'; +import type { IndexPatternLayer } from '../../../types'; import { rangeOperation } from '..'; import { RangeIndexPatternColumn } from './ranges'; import { @@ -28,6 +28,7 @@ import { import { RangePopover } from './advanced_editor'; import { DragDropBuckets } from '../shared_components'; import { getFieldByNameFactory } from '../../../pure_helpers'; +import { IndexPattern } from '../../../../types'; // mocking random id generator function jest.mock('@elastic/eui', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index 0802ae4692f29c..d3c3bd5ceec866 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -17,7 +17,7 @@ import { FieldBasedIndexPatternColumn } from '../column_types'; import { updateColumnParam } from '../../layer_helpers'; import { supportedFormats } from '../../../../../common/expressions/format_column/supported_formats'; import { MODES, AUTO_BARS, DEFAULT_INTERVAL, MIN_HISTOGRAM_BARS, SLICES } from './constants'; -import { IndexPattern, IndexPatternField } from '../../../types'; +import { IndexPattern, IndexPatternField } from '../../../../types'; import { getInvalidFieldMessage, isValidNumber } from '../helpers'; type RangeType = Omit; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/shared_components/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/shared_components/index.tsx index 47cc121be095b2..1dbd20d8767d07 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/shared_components/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/shared_components/index.tsx @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -export * from './label_input'; export * from './buckets'; +export * from './label_input'; export * from './form_row'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx index bf26c3f2ede52a..a93b1ece5e13fc 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.test.tsx @@ -17,7 +17,8 @@ import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { staticValueOperation } from '.'; -import { IndexPattern, IndexPatternLayer } from '../../types'; +import { IndexPatternLayer } from '../../types'; +import { IndexPattern } from '../../../types'; import { StaticValueIndexPatternColumn } from './static_value'; import { TermsIndexPatternColumn } from './terms'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx index f2359d567052fc..61fcb290df95b0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx @@ -13,7 +13,7 @@ import { GenericIndexPatternColumn, ValueFormatConfig, } from './column_types'; -import type { IndexPattern } from '../../types'; +import type { IndexPattern } from '../../../types'; import { useDebouncedValue } from '../../../shared_components'; import { getFormatFromPreviousColumn, isValidNumber } from './helpers'; import { getColumnOrder } from '../layer_helpers'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx index 7fba5b65c9ac3f..5ae10751e64c46 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx @@ -17,13 +17,13 @@ import { useEuiTheme, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { DragDropBuckets, NewBucketButton } from '../shared_components/buckets'; +import { ExistingFieldsMap, IndexPattern } from '../../../../types'; import { TooltipWrapper, useDebouncedValue } from '../../../../shared_components'; import { FieldSelect } from '../../../dimension_panel/field_select'; import type { TermsIndexPatternColumn } from './types'; -import type { IndexPattern, IndexPatternPrivateState } from '../../../types'; import type { OperationSupportMatrix } from '../../../dimension_panel'; import { supportedTypes } from './constants'; +import { DragDropBuckets, NewBucketButton } from '../shared_components'; const generateId = htmlIdGenerator(); export const MAX_MULTI_FIELDS_SIZE = 3; @@ -31,7 +31,7 @@ export const MAX_MULTI_FIELDS_SIZE = 3; export interface FieldInputsProps { column: TermsIndexPatternColumn; indexPattern: IndexPattern; - existingFields: IndexPatternPrivateState['existingFields']; + existingFields: ExistingFieldsMap; invalidFields?: string[]; operationSupportMatrix: Pick; onChange: (newValues: string[]) => void; @@ -183,7 +183,7 @@ export function FieldInputs({ { fields[field.name] = true; } return { - [layer.indexPatternId]: fields, + [defaultProps.indexPattern.title]: fields, }; } @@ -1218,14 +1219,13 @@ describe('terms', () => { return getOperationSupportMatrix({ state: { layers: { layer1: layer }, - indexPatterns: { - [defaultProps.indexPattern.id]: defaultProps.indexPattern, - }, - existingFields, } as unknown as IndexPatternPrivateState, layerId: 'layer1', filterOperations: () => true, columnId, + indexPatterns: { + [defaultProps.indexPattern.id]: defaultProps.indexPattern, + }, }); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts index 5b9354faec3b1a..a865a1de16a772 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts @@ -23,7 +23,7 @@ import { operationDefinitionMap, OperationType } from '.'; import { TermsIndexPatternColumn } from './definitions/terms'; import { DateHistogramIndexPatternColumn } from './definitions/date_histogram'; import { AvgIndexPatternColumn } from './definitions/metrics'; -import type { IndexPattern, IndexPatternLayer, IndexPatternPrivateState } from '../types'; +import type { IndexPatternLayer, IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; import { getFieldByNameFactory } from '../pure_helpers'; import { generateId } from '../../id_generator'; @@ -38,6 +38,7 @@ import { } from './definitions'; import { TinymathAST } from '@kbn/tinymath'; import { CoreStart } from '@kbn/core/public'; +import { IndexPattern } from '../../types'; jest.mock('.'); jest.mock('../../id_generator'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index f7574d01a8350c..3d079584e32f9a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -13,6 +13,8 @@ import type { VisualizeEditorLayersContext } from '@kbn/visualizations-plugin/pu import type { DatasourceFixAction, FrameDatasourceAPI, + IndexPattern, + IndexPatternField, OperationMetadata, VisualizationDimensionGroupConfig, } from '../../types'; @@ -27,8 +29,6 @@ import { } from './definitions'; import type { DataViewDragDropOperation, - IndexPattern, - IndexPatternField, IndexPatternLayer, IndexPatternPrivateState, } from '../types'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts index 396bf78f82db6b..b30c91a7f10844 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts @@ -6,7 +6,7 @@ */ import { memoize } from 'lodash'; -import { OperationMetadata } from '../../types'; +import type { IndexPattern, IndexPatternField, OperationMetadata } from '../../types'; import { operationDefinitionMap, operationDefinitions, @@ -15,7 +15,6 @@ import { renameOperationsMapping, BaseIndexPatternColumn, } from './definitions'; -import { IndexPattern, IndexPatternField } from '../types'; import { documentField } from '../document_field'; import { hasField } from '../pure_utils'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.test.ts deleted file mode 100644 index 90673189b4a83a..00000000000000 --- a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 { fieldExists } from './pure_helpers'; - -describe('fieldExists', () => { - it('returns whether or not a field exists', () => { - expect(fieldExists({ a: { b: true } }, 'a', 'b')).toBeTruthy(); - expect(fieldExists({ a: { b: true } }, 'a', 'c')).toBeFalsy(); - expect(fieldExists({ a: { b: true } }, 'b', 'b')).toBeFalsy(); - }); -}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts index 6c81634fb4c090..ba3ba9bbb824f8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts @@ -6,17 +6,9 @@ */ import { keyBy } from 'lodash'; -import { IndexPatternField, IndexPatternPrivateState } from './types'; +import { IndexPatternField } from '../types'; import { documentField } from './document_field'; -export function fieldExists( - existingFields: IndexPatternPrivateState['existingFields'], - indexPatternTitle: string, - fieldName: string -) { - return existingFields[indexPatternTitle] && existingFields[indexPatternTitle][fieldName]; -} - export function getFieldByNameFactory( newFields: IndexPatternField[], addRecordsField: boolean = true diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/query_input.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/query_input.tsx index 6d69760d51d87b..583f6b28996c9d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/query_input.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/query_input.tsx @@ -20,6 +20,7 @@ export const QueryInput = ({ onSubmit, disableAutoFocus, ['data-test-subj']: dataTestSubj, + placeholder, }: { value: Query; onChange: (input: Query) => void; @@ -28,6 +29,7 @@ export const QueryInput = ({ onSubmit: () => void; disableAutoFocus?: boolean; 'data-test-subj'?: string; + placeholder?: string; }) => { const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange }); @@ -51,7 +53,8 @@ export const QueryInput = ({ } }} placeholder={ - inputValue.language === 'kuery' + placeholder ?? + (inputValue.language === 'kuery' ? i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderKql', { defaultMessage: '{example}', values: { example: 'method : "GET" or status : "404"' }, @@ -59,7 +62,7 @@ export const QueryInput = ({ : i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderLucene', { defaultMessage: '{example}', values: { example: 'method:GET OR status:404' }, - }) + })) } languageSwitcherPopoverAnchorPosition="rightDown" /> diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/time_shift_utils.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/time_shift_utils.tsx index 0391ecce8ac24d..51f389e69a4f06 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/time_shift_utils.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/time_shift_utils.tsx @@ -13,13 +13,12 @@ import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { Datatable } from '@kbn/expressions-plugin/common'; import { search } from '@kbn/data-plugin/public'; import { parseTimeShift } from '@kbn/data-plugin/common'; -import { - IndexPattern, +import type { GenericIndexPatternColumn, IndexPatternLayer, IndexPatternPrivateState, } from './types'; -import { FramePublicAPI } from '../types'; +import type { FramePublicAPI, IndexPattern } from '../types'; export const timeShiftOptions = [ { @@ -193,12 +192,12 @@ export function getDisallowedPreviousShiftMessage( export function getStateTimeShiftWarningMessages( datatableUtilities: DatatableUtilitiesService, state: IndexPatternPrivateState, - { activeData }: FramePublicAPI + { activeData, dataViews }: FramePublicAPI ) { if (!state) return; const warningMessages: React.ReactNode[] = []; Object.entries(state.layers).forEach(([layerId, layer]) => { - const layerIndexPattern = state.indexPatterns[layer.indexPatternId]; + const layerIndexPattern = dataViews.indexPatterns[layer.indexPatternId]; if (!layerIndexPattern) { return; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts index 84d65c91fb52fe..de0f56bb9e21e0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/to_expression.ts @@ -22,10 +22,11 @@ import { } from '@kbn/expressions-plugin/public'; import { GenericIndexPatternColumn } from './indexpattern'; import { operationDefinitionMap } from './operations'; -import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types'; +import { IndexPatternPrivateState, IndexPatternLayer } from './types'; import { DateHistogramIndexPatternColumn, RangeIndexPatternColumn } from './operations/definitions'; import { FormattedIndexPatternColumn } from './operations/definitions/column_types'; import { isColumnFormatted, isColumnOfType } from './operations/definitions/helpers'; +import type { IndexPattern, IndexPatternMap } from '../types'; export type OriginalColumn = { id: string } & GenericIndexPatternColumn; @@ -413,12 +414,13 @@ function sortedReferences(columns: Array; - meta?: boolean; - runtime?: boolean; -}; - export interface IndexPatternLayer { columnOrder: string[]; columns: Record; @@ -86,26 +66,9 @@ export type PersistedIndexPatternLayer = Omit; - indexPatternRefs: IndexPatternRef[]; - indexPatterns: Record; - - /** - * indexPatternId -> fieldName -> boolean - */ - existingFields: Record>; - isFirstExistenceFetch: boolean; - existenceFetchFailed?: boolean; - existenceFetchTimeout?: boolean; - isDimensionClosePrevented?: boolean; } -export interface IndexPatternRef { - id: string; - title: string; - name?: string; -} - export interface DataViewDragDropOperation extends DragDropOperation { dataView: IndexPattern; column?: GenericIndexPatternColumn; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx index 79b87628bd2136..3bfcd51fb39074 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx @@ -41,11 +41,6 @@ describe('indexpattern_datasource utils', () => { }, }, }, - indexPatterns: { - one: { - getFieldByName: (x: string) => ({ name: x, displayName: x }), - }, - }, } as unknown as IndexPatternPrivateState; framePublicAPI = { activeData: { @@ -62,6 +57,13 @@ describe('indexpattern_datasource utils', () => { ], }, }, + dataViews: { + indexPatterns: { + one: { + getFieldByName: (x: string) => ({ name: x, displayName: x }), + }, + }, + }, } as unknown as FramePublicAPI; docLinks = { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx index 85837b10103558..d67023a1a24be8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx @@ -16,8 +16,8 @@ import { EuiLink, EuiTextColor, EuiButton, EuiSpacer } from '@elastic/eui'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { groupBy, escape } from 'lodash'; import type { Query } from '@kbn/data-plugin/common'; -import type { FramePublicAPI, StateSetter } from '../types'; -import type { IndexPattern, IndexPatternLayer, IndexPatternPrivateState } from './types'; +import type { FramePublicAPI, IndexPattern, StateSetter } from '../types'; +import type { IndexPatternLayer, IndexPatternPrivateState } from './types'; import type { ReferenceBasedIndexPatternColumn } from './operations/definitions/column_types'; import { @@ -162,7 +162,7 @@ const accuracyModeEnabledWarning = (columnName: string, docLink: string) => ( export function getPrecisionErrorWarningMessages( datatableUtilities: DatatableUtilitiesService, state: IndexPatternPrivateState, - { activeData }: FramePublicAPI, + { activeData, dataViews }: FramePublicAPI, docLinks: DocLinksStart, setState: StateSetter ) { @@ -181,7 +181,7 @@ export function getPrecisionErrorWarningMessages( const currentLayer = state.layers[layerId]; const currentColumn = currentLayer?.columns[column.id]; if (currentLayer && currentColumn && datatableUtilities.hasPrecisionError(column)) { - const indexPattern = state.indexPatterns[currentLayer.indexPatternId]; + const indexPattern = dataViews.indexPatterns[currentLayer.indexPatternId]; // currentColumnIsTerms is mostly a type guard. If there's a precision error, // we already know that we're dealing with a terms-based operation (at least for now). const currentColumnIsTerms = isColumnOfType( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/window_utils.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/window_utils.tsx index 14cc09fcdec8b9..26b1feaa45eaa0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/window_utils.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/window_utils.tsx @@ -6,7 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { IndexPattern, IndexPatternLayer } from './types'; +import type { IndexPatternLayer } from './types'; +import type { IndexPattern } from '../types'; export const windowOptions = [ { diff --git a/x-pack/plugins/lens/public/indexpattern_service/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_service/loader.test.ts new file mode 100644 index 00000000000000..912028fba81a29 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_service/loader.test.ts @@ -0,0 +1,435 @@ +/* + * 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 { HttpHandler } from '@kbn/core/public'; +import { last } from 'lodash'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { createHttpFetchError } from '@kbn/core-http-browser-mocks'; +import { IndexPattern, IndexPatternField } from '../types'; +import { + ensureIndexPattern, + loadIndexPatternRefs, + loadIndexPatterns, + syncExistingFields, +} from './loader'; +import { sampleIndexPatterns, mockDataViewsService } from './mocks'; +import { documentField } from '../indexpattern_datasource/document_field'; + +describe('loader', () => { + describe('loadIndexPatternRefs', () => { + it('should return a list of sorted indexpattern refs', async () => { + const refs = await loadIndexPatternRefs(mockDataViewsService()); + expect(refs[0].title < refs[1].title).toBeTruthy(); + }); + }); + + describe('loadIndexPatterns', () => { + it('should not load index patterns that are already loaded', async () => { + const dataViewsService = mockDataViewsService(); + dataViewsService.get = jest.fn(() => + Promise.reject('mockIndexPatternService.get should not have been called') + ); + + const cache = await loadIndexPatterns({ + cache: sampleIndexPatterns, + patterns: ['1', '2'], + dataViews: dataViewsService, + }); + + expect(cache).toEqual(sampleIndexPatterns); + }); + + it('should load index patterns that are not loaded', async () => { + const cache = await loadIndexPatterns({ + cache: { + '2': sampleIndexPatterns['2'], + }, + patterns: ['1', '2'], + dataViews: mockDataViewsService(), + }); + + expect(Object.keys(cache)).toEqual(['1', '2']); + }); + + it('should apply field restrictions from typeMeta', async () => { + const cache = await loadIndexPatterns({ + cache: {}, + patterns: ['foo'], + dataViews: { + get: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + metaFields: [], + typeMeta: { + aggs: { + date_histogram: { + timestamp: { + agg: 'date_histogram', + fixed_interval: 'm', + }, + }, + sum: { + bytes: { + agg: 'sum', + }, + }, + }, + }, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + })), + getIdsWithTitle: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + })), + } as unknown as Pick, + }); + + expect(cache.foo.getFieldByName('bytes')!.aggregationRestrictions).toEqual({ + sum: { agg: 'sum' }, + }); + expect(cache.foo.getFieldByName('timestamp')!.aggregationRestrictions).toEqual({ + date_histogram: { agg: 'date_histogram', fixed_interval: 'm' }, + }); + }); + + it('should map meta flag', async () => { + const cache = await loadIndexPatterns({ + cache: {}, + patterns: ['foo'], + dataViews: { + get: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + metaFields: ['timestamp'], + typeMeta: { + aggs: { + date_histogram: { + timestamp: { + agg: 'date_histogram', + fixed_interval: 'm', + }, + }, + sum: { + bytes: { + agg: 'sum', + }, + }, + }, + }, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + })), + getIdsWithTitle: jest.fn(async () => ({ + id: 'foo', + title: 'Foo index', + })), + } as unknown as Pick, + }); + + expect(cache.foo.getFieldByName('timestamp')!.meta).toEqual(true); + }); + + it('should call the refresh callback when loading new indexpatterns', async () => { + const onIndexPatternRefresh = jest.fn(); + await loadIndexPatterns({ + cache: { + '2': sampleIndexPatterns['2'], + }, + patterns: ['1', '2'], + dataViews: mockDataViewsService(), + onIndexPatternRefresh, + }); + + expect(onIndexPatternRefresh).toHaveBeenCalled(); + }); + + it('should not call the refresh callback when using the cache', async () => { + const onIndexPatternRefresh = jest.fn(); + await loadIndexPatterns({ + cache: sampleIndexPatterns, + patterns: ['1', '2'], + dataViews: mockDataViewsService(), + onIndexPatternRefresh, + }); + + expect(onIndexPatternRefresh).not.toHaveBeenCalled(); + }); + + it('should load one of the not used indexpatterns if all used ones are not available', async () => { + const dataViewsService = { + get: jest.fn(async (id: string) => { + if (id === '3') { + return { + id: '3', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: [], + }; + } + return Promise.reject(); + }), + getIdsWithTitle: jest.fn(), + } as unknown as Pick; + const cache = await loadIndexPatterns({ + cache: {}, + patterns: ['1', '2'], + notUsedPatterns: ['3'], + dataViews: dataViewsService, + }); + + expect(cache).toEqual({ + 3: expect.objectContaining({ + id: '3', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: [documentField], + }), + }); + }); + }); + + describe('ensureIndexPattern', () => { + it('should throw if the requested indexPattern cannot be loaded', async () => { + const err = Error('NOPE!'); + const onError = jest.fn(); + const cache = await ensureIndexPattern({ + id: '3', + dataViews: { + get: jest.fn(async () => { + throw err; + }), + getIdsWithTitle: jest.fn(), + } as unknown as Pick, + onError, + }); + + expect(cache).toBeUndefined(); + expect(onError).toHaveBeenCalledWith(Error('Missing indexpatterns')); + }); + + it('should ensure the requested indexpattern is loaded into the cache', async () => { + const onError = jest.fn(); + const cache = await ensureIndexPattern({ + id: '2', + dataViews: mockDataViewsService(), + onError, + }); + expect(cache).toEqual({ 2: expect.anything() }); + expect(onError).not.toHaveBeenCalled(); + }); + }); + + describe('syncExistingFields', () => { + const dslQuery = { + bool: { + must: [], + filter: [{ match_all: {} }], + should: [], + must_not: [], + }, + }; + + function getIndexPatternList() { + return [ + { id: '1', title: '1', fields: [], hasRestrictions: false }, + { id: '2', title: '1', fields: [], hasRestrictions: false }, + { id: '3', title: '1', fields: [], hasRestrictions: false }, + ] as unknown as IndexPattern[]; + } + + it('should call once for each index pattern', async () => { + const updateIndexPatterns = jest.fn(); + const fetchJson = jest.fn((path: string) => { + const indexPatternTitle = last(path.split('/')); + return { + indexPatternTitle, + existingFieldNames: ['field_1', 'field_2'].map( + (fieldName) => `ip${indexPatternTitle}_${fieldName}` + ), + }; + }) as unknown as HttpHandler; + + await syncExistingFields({ + dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, + fetchJson, + indexPatternList: getIndexPatternList(), + updateIndexPatterns, + dslQuery, + onNoData: jest.fn(), + currentIndexPatternTitle: 'abc', + isFirstExistenceFetch: false, + existingFields: {}, + }); + + expect(fetchJson).toHaveBeenCalledTimes(3); + expect(updateIndexPatterns).toHaveBeenCalledTimes(1); + + const [newState, options] = updateIndexPatterns.mock.calls[0]; + expect(options).toEqual({ applyImmediately: true }); + + expect(newState).toEqual({ + isFirstExistenceFetch: false, + existingFields: { + '1': { ip1_field_1: true, ip1_field_2: true }, + '2': { ip2_field_1: true, ip2_field_2: true }, + '3': { ip3_field_1: true, ip3_field_2: true }, + }, + }); + }); + + it('should call onNoData callback if current index pattern returns no fields', async () => { + const updateIndexPatterns = jest.fn(); + const onNoData = jest.fn(); + const fetchJson = jest.fn((path: string) => { + const indexPatternTitle = last(path.split('/')); + return { + indexPatternTitle, + existingFieldNames: + indexPatternTitle === '1' + ? ['field_1', 'field_2'].map((fieldName) => `${indexPatternTitle}_${fieldName}`) + : [], + }; + }) as unknown as HttpHandler; + + const args = { + dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, + fetchJson, + indexPatternList: getIndexPatternList(), + updateIndexPatterns, + dslQuery, + onNoData, + currentIndexPatternTitle: 'abc', + isFirstExistenceFetch: false, + existingFields: {}, + }; + + await syncExistingFields(args); + + expect(onNoData).not.toHaveBeenCalled(); + + await syncExistingFields({ ...args, isFirstExistenceFetch: true }); + expect(onNoData).not.toHaveBeenCalled(); + }); + + it('should set all fields to available and existence error flag if the request fails', async () => { + const updateIndexPatterns = jest.fn(); + const fetchJson = jest.fn((path: string) => { + return new Promise((resolve, reject) => { + reject(new Error()); + }); + }) as unknown as HttpHandler; + + const args = { + dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, + fetchJson, + indexPatternList: [ + { + id: '1', + title: '1', + hasRestrictions: false, + fields: [{ name: 'field1' }, { name: 'field2' }] as IndexPatternField[], + }, + ] as IndexPattern[], + updateIndexPatterns, + dslQuery, + onNoData: jest.fn(), + currentIndexPatternTitle: 'abc', + isFirstExistenceFetch: false, + existingFields: {}, + }; + + await syncExistingFields(args); + + const [newState, options] = updateIndexPatterns.mock.calls[0]; + expect(options).toEqual({ applyImmediately: true }); + + expect(newState.existenceFetchFailed).toEqual(true); + expect(newState.existenceFetchTimeout).toEqual(false); + expect(newState.existingFields['1']).toEqual({ + field1: true, + field2: true, + }); + }); + + it('should set all fields to available and existence error flag if the request times out', async () => { + const updateIndexPatterns = jest.fn(); + const fetchJson = jest.fn((path: string) => { + return new Promise((resolve, reject) => { + const error = createHttpFetchError( + 'timeout', + 'error', + {} as Request, + { status: 408 } as Response + ); + reject(error); + }); + }) as unknown as HttpHandler; + + const args = { + dateRange: { fromDate: '1900-01-01', toDate: '2000-01-01' }, + fetchJson, + indexPatternList: [ + { + id: '1', + title: '1', + hasRestrictions: false, + fields: [{ name: 'field1' }, { name: 'field2' }] as IndexPatternField[], + }, + ] as IndexPattern[], + updateIndexPatterns, + dslQuery, + onNoData: jest.fn(), + currentIndexPatternTitle: 'abc', + isFirstExistenceFetch: false, + existingFields: {}, + }; + + await syncExistingFields(args); + + const [newState, options] = updateIndexPatterns.mock.calls[0]; + expect(options).toEqual({ applyImmediately: true }); + + expect(newState.existenceFetchFailed).toEqual(false); + expect(newState.existenceFetchTimeout).toEqual(true); + expect(newState.existingFields['1']).toEqual({ + field1: true, + field2: true, + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_service/loader.ts b/x-pack/plugins/lens/public/indexpattern_service/loader.ts new file mode 100644 index 00000000000000..45dd7eb9db8f32 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_service/loader.ts @@ -0,0 +1,311 @@ +/* + * 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 { isNestedField } from '@kbn/data-views-plugin/common'; +import type { DataViewsContract, DataView } from '@kbn/data-views-plugin/public'; +import { keyBy } from 'lodash'; +import { HttpSetup } from '@kbn/core/public'; +import { IndexPattern, IndexPatternField, IndexPatternMap, IndexPatternRef } from '../types'; +import { documentField } from '../indexpattern_datasource/document_field'; +import { BASE_API_URL, DateRange, ExistingFields } from '../../common'; +import { DataViewsState } from '../state_management'; + +type ErrorHandler = (err: Error) => void; +type MinimalDataViewsContract = Pick; + +/** + * All these functions will be used by the Embeddable instance too, + * therefore keep all these functions pretty raw here and do not use the IndexPatternService + */ + +export function getFieldByNameFactory(newFields: IndexPatternField[]) { + const fieldsLookup = keyBy(newFields, 'name'); + return (name: string) => fieldsLookup[name]; +} + +export function convertDataViewIntoLensIndexPattern( + dataView: DataView, + restrictionRemapper: (name: string) => string = onRestrictionMapping +): IndexPattern { + const newFields = dataView.fields + .filter((field) => !isNestedField(field) && (!!field.aggregatable || !!field.scripted)) + .map((field): IndexPatternField => { + // Convert the getters on the index pattern service into plain JSON + const base = { + name: field.name, + displayName: field.displayName, + type: field.type, + aggregatable: field.aggregatable, + searchable: field.searchable, + meta: dataView.metaFields.includes(field.name), + esTypes: field.esTypes, + scripted: field.scripted, + runtime: Boolean(field.runtimeField), + }; + + // Simplifies tests by hiding optional properties instead of undefined + return base.scripted + ? { + ...base, + lang: field.lang, + script: field.script, + } + : base; + }) + .concat(documentField); + + const { typeMeta, title, name, timeFieldName, fieldFormatMap } = dataView; + if (typeMeta?.aggs) { + const aggs = Object.keys(typeMeta.aggs); + newFields.forEach((field, index) => { + const restrictionsObj: IndexPatternField['aggregationRestrictions'] = {}; + aggs.forEach((agg) => { + const restriction = typeMeta.aggs && typeMeta.aggs[agg] && typeMeta.aggs[agg][field.name]; + if (restriction) { + restrictionsObj[restrictionRemapper(agg)] = restriction; + } + }); + if (Object.keys(restrictionsObj).length) { + newFields[index] = { ...field, aggregationRestrictions: restrictionsObj }; + } + }); + } + + return { + id: dataView.id!, // id exists for sure because we got index patterns by id + title, + name: name ? name : title, + timeFieldName, + fieldFormatMap: + fieldFormatMap && + Object.fromEntries( + Object.entries(fieldFormatMap).map(([id, format]) => [ + id, + // @ts-ignore + 'toJSON' in format ? format.toJSON() : format, + ]) + ), + fields: newFields, + getFieldByName: getFieldByNameFactory(newFields), + hasRestrictions: !!typeMeta?.aggs, + }; +} + +export async function loadIndexPatternRefs( + dataViews: MinimalDataViewsContract +): Promise { + const indexPatterns = await dataViews.getIdsWithTitle(); + + return indexPatterns.sort((a, b) => { + return a.title.localeCompare(b.title); + }); +} + +/** + * Map ES agg names with Lens ones + */ +const renameOperationsMapping: Record = { + avg: 'average', + cardinality: 'unique_count', +}; + +function onRestrictionMapping(agg: string): string { + return agg in renameOperationsMapping ? renameOperationsMapping[agg] : agg; +} + +export async function loadIndexPatterns({ + dataViews, + patterns, + notUsedPatterns, + cache, + onIndexPatternRefresh, +}: { + dataViews: MinimalDataViewsContract; + patterns: string[]; + notUsedPatterns?: string[]; + cache: Record; + onIndexPatternRefresh?: () => void; +}) { + const missingIds = patterns.filter((id) => !cache[id]); + + if (missingIds.length === 0) { + return cache; + } + + onIndexPatternRefresh?.(); + + const allIndexPatterns = await Promise.allSettled(missingIds.map((id) => dataViews.get(id))); + // ignore rejected indexpatterns here, they're already handled at the app level + let indexPatterns = allIndexPatterns + .filter( + (response): response is PromiseFulfilledResult => response.status === 'fulfilled' + ) + .map((response) => response.value); + + // if all of the used index patterns failed to load, try loading one of not used ones till one succeeds + if (!indexPatterns.length && notUsedPatterns) { + for (const notUsedPattern of notUsedPatterns) { + const resp = await dataViews.get(notUsedPattern).catch((e) => { + // do nothing + }); + if (resp) { + indexPatterns = [resp]; + } + } + } + + const indexPatternsObject = indexPatterns.reduce( + (acc, indexPattern) => ({ + [indexPattern.id!]: convertDataViewIntoLensIndexPattern(indexPattern, onRestrictionMapping), + ...acc, + }), + { ...cache } + ); + + return indexPatternsObject; +} + +export async function ensureIndexPattern({ + id, + onError, + dataViews, + cache = {}, +}: { + id: string; + onError: ErrorHandler; + dataViews: MinimalDataViewsContract; + cache?: IndexPatternMap; +}) { + const indexPatterns = await loadIndexPatterns({ + dataViews, + cache, + patterns: [id], + }); + + if (indexPatterns[id] == null) { + onError(Error('Missing indexpatterns')); + return; + } + + const newIndexPatterns = { + ...cache, + [id]: indexPatterns[id], + }; + return newIndexPatterns; +} + +async function refreshExistingFields({ + dateRange, + fetchJson, + indexPatternList, + dslQuery, +}: { + dateRange: DateRange; + indexPatternList: IndexPattern[]; + fetchJson: HttpSetup['post']; + dslQuery: object; +}) { + try { + const emptinessInfo = await Promise.all( + indexPatternList.map((pattern) => { + if (pattern.hasRestrictions) { + return { + indexPatternTitle: pattern.title, + existingFieldNames: pattern.fields.map((field) => field.name), + }; + } + const body: Record = { + dslQuery, + fromDate: dateRange.fromDate, + toDate: dateRange.toDate, + }; + + if (pattern.timeFieldName) { + body.timeFieldName = pattern.timeFieldName; + } + + return fetchJson(`${BASE_API_URL}/existing_fields/${pattern.id}`, { + body: JSON.stringify(body), + }) as Promise; + }) + ); + return { result: emptinessInfo, status: 200 }; + } catch (e) { + return { result: undefined, status: e.res?.status as number }; + } +} + +type FieldsPropsFromDataViewsState = Pick< + DataViewsState, + 'existingFields' | 'isFirstExistenceFetch' | 'existenceFetchTimeout' | 'existenceFetchFailed' +>; +export async function syncExistingFields({ + updateIndexPatterns, + isFirstExistenceFetch, + currentIndexPatternTitle, + onNoData, + existingFields, + ...requestOptions +}: { + dateRange: DateRange; + indexPatternList: IndexPattern[]; + existingFields: Record>; + fetchJson: HttpSetup['post']; + updateIndexPatterns: ( + newFieldState: FieldsPropsFromDataViewsState, + options: { applyImmediately: boolean } + ) => void; + isFirstExistenceFetch: boolean; + currentIndexPatternTitle: string; + dslQuery: object; + onNoData?: () => void; +}) { + const { indexPatternList } = requestOptions; + const newExistingFields = { ...existingFields }; + + const { result, status } = await refreshExistingFields(requestOptions); + + if (result) { + if (isFirstExistenceFetch) { + const fieldsCurrentIndexPattern = result.find( + (info) => info.indexPatternTitle === currentIndexPatternTitle + ); + if (fieldsCurrentIndexPattern && fieldsCurrentIndexPattern.existingFieldNames.length === 0) { + onNoData?.(); + } + } + + for (const { indexPatternTitle, existingFieldNames } of result) { + newExistingFields[indexPatternTitle] = booleanMap(existingFieldNames); + } + } else { + for (const { title, fields } of indexPatternList) { + newExistingFields[title] = booleanMap(fields.map((field) => field.name)); + } + } + + updateIndexPatterns( + { + existingFields: newExistingFields, + ...(result + ? { isFirstExistenceFetch: status !== 200 } + : { + isFirstExistenceFetch, + existenceFetchFailed: status !== 408, + existenceFetchTimeout: status === 408, + }), + }, + { applyImmediately: true } + ); +} + +function booleanMap(keys: string[]) { + return keys.reduce((acc, key) => { + acc[key] = true; + return acc; + }, {} as Record); +} diff --git a/x-pack/plugins/lens/public/indexpattern_service/mocks.ts b/x-pack/plugins/lens/public/indexpattern_service/mocks.ts new file mode 100644 index 00000000000000..6eb7156a91cffd --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_service/mocks.ts @@ -0,0 +1,220 @@ +/* + * 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 { DataViewsContract } from '@kbn/data-views-plugin/common'; +import { documentField } from '../indexpattern_datasource/document_field'; +import { + createMockedIndexPattern, + createMockedRestrictedIndexPattern, +} from '../indexpattern_datasource/mocks'; +import { IndexPattern } from '../types'; +import { getFieldByNameFactory } from './loader'; + +export function loadInitialDataViews() { + const indexPattern = createMockedIndexPattern(); + const restricted = createMockedRestrictedIndexPattern(); + return { + indexPatternRefs: [], + existingFields: {}, + indexPatterns: { + [indexPattern.id]: indexPattern, + [restricted.id]: restricted, + }, + isFirstExistenceFetch: false, + }; +} + +export const createMockStorage = (lastData?: Record) => { + return { + get: jest.fn().mockImplementation(() => lastData), + set: jest.fn(), + remove: jest.fn(), + clear: jest.fn(), + }; +}; + +const indexPattern1 = { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'start_date', + displayName: 'start_date', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + esTypes: ['keyword'], + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + esTypes: ['keyword'], + }, + { + name: 'geo.src', + displayName: 'geo.src', + type: 'string', + aggregatable: true, + searchable: true, + esTypes: ['keyword'], + }, + { + name: 'scripted', + displayName: 'Scripted', + type: 'string', + searchable: true, + aggregatable: true, + scripted: true, + lang: 'painless', + script: '1234', + }, + documentField, + ], +} as unknown as IndexPattern; +indexPattern1.getFieldByName = getFieldByNameFactory(indexPattern1.fields); + +const sampleIndexPatternsFromService = { + '1': createMockedIndexPattern(), + '2': createMockedRestrictedIndexPattern(), +}; + +const indexPattern2 = { + id: '2', + title: 'my-fake-restricted-pattern', + timeFieldName: 'timestamp', + hasRestrictions: true, + fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + // Ignored in the UI + histogram: { + agg: 'histogram', + interval: 1000, + }, + average: { + agg: 'avg', + }, + max: { + agg: 'max', + }, + min: { + agg: 'min', + }, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + scripted: true, + lang: 'painless', + script: '1234', + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, + documentField, + ], +} as unknown as IndexPattern; +indexPattern2.getFieldByName = getFieldByNameFactory(indexPattern2.fields); + +export const sampleIndexPatterns = { + '1': indexPattern1, + '2': indexPattern2, +}; + +export function mockDataViewsService() { + return { + get: jest.fn(async (id: '1' | '2') => { + const result = { ...sampleIndexPatternsFromService[id], metaFields: [] }; + if (!result.fields) { + result.fields = []; + } + return result; + }), + getIdsWithTitle: jest.fn(async () => { + return [ + { + id: sampleIndexPatterns[1].id, + title: sampleIndexPatterns[1].title, + }, + { + id: sampleIndexPatterns[2].id, + title: sampleIndexPatterns[2].title, + }, + ]; + }), + } as unknown as Pick; +} diff --git a/x-pack/plugins/lens/public/indexpattern_service/service.ts b/x-pack/plugins/lens/public/indexpattern_service/service.ts new file mode 100644 index 00000000000000..bbce7f83cf25ae --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_service/service.ts @@ -0,0 +1,118 @@ +/* + * 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 type { DataViewsContract } from '@kbn/data-views-plugin/public'; +import type { CoreStart, IUiSettingsClient } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import type { DateRange } from '../../common'; +import type { IndexPattern, IndexPatternMap, IndexPatternRef } from '../types'; +import { + ensureIndexPattern, + loadIndexPatternRefs, + loadIndexPatterns, + syncExistingFields, +} from './loader'; +import type { DataViewsState } from '../state_management'; + +export interface IndexPatternServiceProps { + core: Pick; + dataViews: DataViewsContract; + uiSettings: IUiSettingsClient; + updateIndexPatterns: ( + newState: Partial, + options?: { applyImmediately: boolean } + ) => void; +} + +/** + * This service is only available for the full editor version + * and it encapsulate all the indexpattern methods and state + * in a single object. + * NOTE: this is not intended to be used with the Embeddable branch + */ +export interface IndexPatternServiceAPI { + /** + * Loads a list of indexPatterns from a list of id (patterns) + * leveraging existing cache. Eventually fallbacks to unused indexPatterns ( notUsedPatterns ) + * @returns IndexPatternMap + */ + loadIndexPatterns: (args: { + patterns: string[]; + notUsedPatterns?: string[]; + cache: IndexPatternMap; + onIndexPatternRefresh?: () => void; + }) => Promise; + /** + * Load indexPatternRefs with title and ids + */ + loadIndexPatternRefs: (options: { isFullEditor: boolean }) => Promise; + /** + * Ensure an indexPattern is loaded in the cache, usually used in conjuction with a indexPattern change action. + */ + ensureIndexPattern: (args: { + id: string; + cache: IndexPatternMap; + }) => Promise; + /** + * Loads the existingFields map given the current context + */ + refreshExistingFields: (args: { + dateRange: DateRange; + currentIndexPatternTitle: string; + dslQuery: object; + onNoData?: () => void; + existingFields: Record>; + indexPatternList: IndexPattern[]; + isFirstExistenceFetch: boolean; + }) => Promise; + /** + * Retrieves the default indexPattern from the uiSettings + */ + getDefaultIndex: () => string; + + /** + * Update the Lens dataViews state + */ + updateDataViewsState: ( + newState: Partial, + options?: { applyImmediately: boolean } + ) => void; +} + +export function createIndexPatternService({ + core, + dataViews, + uiSettings, + updateIndexPatterns, +}: IndexPatternServiceProps): IndexPatternServiceAPI { + const onChangeError = (err: Error) => + core.notifications.toasts.addError(err, { + title: i18n.translate('xpack.lens.indexPattern.dataViewLoadError', { + defaultMessage: 'Error loading data view', + }), + }); + return { + updateDataViewsState: updateIndexPatterns, + loadIndexPatterns: (args) => { + return loadIndexPatterns({ + dataViews, + ...args, + }); + }, + ensureIndexPattern: (args) => + ensureIndexPattern({ onError: onChangeError, dataViews, ...args }), + refreshExistingFields: (args) => + syncExistingFields({ + updateIndexPatterns, + fetchJson: core.http.post, + ...args, + }), + loadIndexPatternRefs: async ({ isFullEditor }) => + isFullEditor ? loadIndexPatternRefs(dataViews) : [], + getDefaultIndex: () => uiSettings.get('defaultIndex'), + }; +} diff --git a/x-pack/plugins/lens/public/mocks/data_views_service_mock.ts b/x-pack/plugins/lens/public/mocks/data_views_service_mock.ts new file mode 100644 index 00000000000000..56ff7015bdb556 --- /dev/null +++ b/x-pack/plugins/lens/public/mocks/data_views_service_mock.ts @@ -0,0 +1,24 @@ +/* + * 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 { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; +import { coreMock } from '@kbn/core/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { + createIndexPatternService, + IndexPatternServiceProps, + IndexPatternServiceAPI, +} from '../indexpattern_service/service'; + +export function createIndexPatternServiceMock({ + core = coreMock.createStart(), + uiSettings = uiSettingsServiceMock.createStartContract(), + dataViews = dataViewPluginMocks.createStartContract(), + updateIndexPatterns = jest.fn(), +}: Partial = {}): IndexPatternServiceAPI { + return createIndexPatternService({ core, uiSettings, updateIndexPatterns, dataViews }); +} diff --git a/x-pack/plugins/lens/public/mocks/datasource_mock.ts b/x-pack/plugins/lens/public/mocks/datasource_mock.ts index 90bb1ea9f5cab2..8111270cc5d124 100644 --- a/x-pack/plugins/lens/public/mocks/datasource_mock.ts +++ b/x-pack/plugins/lens/public/mocks/datasource_mock.ts @@ -25,21 +25,23 @@ export function createMockDatasource(id: string): DatasourceMock { return { id: 'testDatasource', clearLayer: jest.fn((state, _layerId) => state), - getDatasourceSuggestionsForField: jest.fn((_state, _item, filterFn) => []), - getDatasourceSuggestionsForVisualizeField: jest.fn((_state, _indexpatternId, _fieldName) => []), - getDatasourceSuggestionsForVisualizeCharts: jest.fn((_state, _context) => []), - getDatasourceSuggestionsFromCurrentState: jest.fn((_state) => []), + getDatasourceSuggestionsForField: jest.fn((_state, _item, filterFn, _indexPatterns) => []), + getDatasourceSuggestionsForVisualizeField: jest.fn( + (_state, _indexpatternId, _fieldName, _indexPatterns) => [] + ), + getDatasourceSuggestionsForVisualizeCharts: jest.fn((_state, _context, _indexPatterns) => []), + getDatasourceSuggestionsFromCurrentState: jest.fn((_state, _indexPatterns) => []), getPersistableState: jest.fn((x) => ({ state: x, savedObjectReferences: [{ type: 'index-pattern', id: 'mockip', name: 'mockip' }], })), getRenderEventCounters: jest.fn((_state) => []), getPublicAPI: jest.fn().mockReturnValue(publicAPIMock), - initialize: jest.fn((_state?) => Promise.resolve()), + initialize: jest.fn((_state?) => {}), renderDataPanel: jest.fn(), renderLayerPanel: jest.fn(), getCurrentIndexPatternId: jest.fn(), - toExpression: jest.fn((_frame, _state) => null), + toExpression: jest.fn((_frame, _state, _indexPatterns) => null), insertLayer: jest.fn((_state, _newLayerId) => ({})), removeLayer: jest.fn((_state, _layerId) => {}), removeColumn: jest.fn((props) => {}), @@ -53,12 +55,13 @@ export function createMockDatasource(id: string): DatasourceMock { // this is an additional property which doesn't exist on real datasources // but can be used to validate whether specific API mock functions are called publicAPIMock, - getErrorMessages: jest.fn((_state) => undefined), - checkIntegrity: jest.fn((_state) => []), + getErrorMessages: jest.fn((_state, _indexPatterns) => undefined), + checkIntegrity: jest.fn((_state, _indexPatterns) => []), isTimeBased: jest.fn(), isValidColumn: jest.fn(), isEqual: jest.fn(), getUsedDataView: jest.fn(), + onRefreshIndexPattern: jest.fn(), }; } diff --git a/x-pack/plugins/lens/public/mocks/index.ts b/x-pack/plugins/lens/public/mocks/index.ts index 58ef8ce05c613d..0d90e719ebadee 100644 --- a/x-pack/plugins/lens/public/mocks/index.ts +++ b/x-pack/plugins/lens/public/mocks/index.ts @@ -32,6 +32,12 @@ export type FrameMock = jest.Mocked; export const createMockFramePublicAPI = (): FrameMock => ({ datasourceLayers: {}, dateRange: { fromDate: '2022-03-17T08:25:00.000Z', toDate: '2022-04-17T08:25:00.000Z' }, + dataViews: { + indexPatterns: {}, + indexPatternRefs: [], + isFirstExistenceFetch: true, + existingFields: {}, + }, }); export type FrameDatasourceMock = jest.Mocked; @@ -41,4 +47,10 @@ export const createMockFrameDatasourceAPI = (): FrameDatasourceMock => ({ dateRange: { fromDate: '2022-03-17T08:25:00.000Z', toDate: '2022-04-17T08:25:00.000Z' }, query: { query: '', language: 'lucene' }, filters: [], + dataViews: { + indexPatterns: {}, + indexPatternRefs: [], + isFirstExistenceFetch: true, + existingFields: {}, + }, }); diff --git a/x-pack/plugins/lens/public/mocks/services_mock.tsx b/x-pack/plugins/lens/public/mocks/services_mock.tsx index 800ec3dee25b1d..e9d0c7cd14f280 100644 --- a/x-pack/plugins/lens/public/mocks/services_mock.tsx +++ b/x-pack/plugins/lens/public/mocks/services_mock.tsx @@ -86,9 +86,10 @@ export function makeDefaultServices( const dataViewsMock = dataViewPluginMocks.createStartContract(); dataViewsMock.get.mockImplementation( jest.fn((id) => - Promise.resolve({ id, isTimeBased: () => true }) + Promise.resolve({ id, isTimeBased: () => true, fields: [] }) ) as unknown as DataViewsPublicPluginStart['get'] ); + dataViewsMock.getIdsWithTitle.mockImplementation(jest.fn(async () => [])); const navigationStartMock = navigationPluginMock.createStartContract(); diff --git a/x-pack/plugins/lens/public/mocks/store_mocks.tsx b/x-pack/plugins/lens/public/mocks/store_mocks.tsx index 2e6bc86a9d33e2..e63a79693cadb5 100644 --- a/x-pack/plugins/lens/public/mocks/store_mocks.tsx +++ b/x-pack/plugins/lens/public/mocks/store_mocks.tsx @@ -58,6 +58,12 @@ export const defaultState = { activeId: 'testVis', }, datasourceStates: mockDatasourceStates(), + dataViews: { + indexPatterns: {}, + indexPatternRefs: [], + existingFields: {}, + isFirstExistenceFetch: false, + }, }; export function makeLensStore({ @@ -78,7 +84,7 @@ export function makeLensStore({ resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), ...preloadedState, }, - } as PreloadedState); + } as unknown as PreloadedState); const origDispatch = store.dispatch; store.dispatch = jest.fn(dispatch || origDispatch); diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 345a27a1e01a00..67303fe4ec617a 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -12,6 +12,7 @@ import type { UsageCollectionSetup, UsageCollectionStart, } from '@kbn/usage-collection-plugin/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; @@ -282,11 +283,16 @@ export class LensPlugin { data: plugins.data, timefilter: plugins.data.query.timefilter.timefilter, expressionRenderer: plugins.expressions.ReactExpressionRenderer, - documentToExpression: this.editorFrameService!.documentToExpression, + documentToExpression: (doc) => + this.editorFrameService!.documentToExpression(doc, { + dataViews: plugins.dataViews, + storage: new Storage(localStorage), + uiSettings: core.uiSettings, + }), injectFilterReferences: data.query.filterManager.inject.bind(data.query.filterManager), visualizationMap, datasourceMap, - indexPatternService: plugins.dataViews, + dataViews: plugins.dataViews, uiActions: plugins.uiActions, usageCollection, inspector: plugins.inspector, diff --git a/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx b/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx new file mode 100644 index 00000000000000..b66a5f1d765457 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/dataview_picker/dataview_picker.tsx @@ -0,0 +1,93 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; +import { EuiPopover, EuiPopoverTitle, EuiSelectableProps } from '@elastic/eui'; +import { ToolbarButton, ToolbarButtonProps } from '@kbn/kibana-react-plugin/public'; +import { DataViewsList } from '@kbn/unified-search-plugin/public'; +import { IndexPatternRef } from '../../types'; + +export type ChangeIndexPatternTriggerProps = ToolbarButtonProps & { + label: string; + title?: string; +}; + +export function ChangeIndexPattern({ + indexPatternRefs, + isMissingCurrent, + indexPatternId, + onChangeIndexPattern, + trigger, + selectableProps, +}: { + trigger: ChangeIndexPatternTriggerProps; + indexPatternRefs: IndexPatternRef[]; + isMissingCurrent?: boolean; + onChangeIndexPattern: (newId: string) => void; + indexPatternId?: string; + selectableProps?: EuiSelectableProps; +}) { + const [isPopoverOpen, setPopoverIsOpen] = useState(false); + + // be careful to only add color with a value, otherwise it will fallbacks to "primary" + const colorProp = isMissingCurrent + ? { + color: 'danger' as const, + } + : {}; + + const createTrigger = function () { + const { label, title, ...rest } = trigger; + return ( + setPopoverIsOpen(!isPopoverOpen)} + fullWidth + {...colorProp} + {...rest} + > + {label} + + ); + }; + + return ( + <> + setPopoverIsOpen(false)} + display="block" + panelPaddingSize="none" + ownFocus + > +
    + + {i18n.translate('xpack.lens.indexPattern.changeDataViewTitle', { + defaultMessage: 'Data view', + })} + + + { + onChangeIndexPattern(newId); + setPopoverIsOpen(false); + }} + currentDataViewId={indexPatternId} + selectableProps={selectableProps} + /> +
    +
    + + ); +} diff --git a/x-pack/plugins/lens/public/shared_components/dataview_picker/helpers.ts b/x-pack/plugins/lens/public/shared_components/dataview_picker/helpers.ts new file mode 100644 index 00000000000000..4f53930fa49732 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/dataview_picker/helpers.ts @@ -0,0 +1,29 @@ +/* + * 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 { IndexPattern } from '../../types'; + +/** + * Checks if the provided field contains data (works for meta field) + */ +export function fieldContainsData( + field: string, + indexPattern: IndexPattern, + existingFields: Record +) { + return ( + indexPattern.getFieldByName(field)?.type === 'document' || fieldExists(existingFields, field) + ); +} + +/** + * Performs an existence check on the existingFields data structure for the provided field. + * Does not work for meta fields. + */ +export function fieldExists(existingFields: Record, fieldName: string) { + return existingFields[fieldName]; +} diff --git a/x-pack/plugins/lens/public/shared_components/dataview_picker/index.ts b/x-pack/plugins/lens/public/shared_components/dataview_picker/index.ts new file mode 100644 index 00000000000000..4de03b2f8b92c3 --- /dev/null +++ b/x-pack/plugins/lens/public/shared_components/dataview_picker/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { ChangeIndexPattern } from './dataview_picker'; +export { fieldExists, fieldContainsData } from './helpers'; diff --git a/x-pack/plugins/lens/public/shared_components/field_picker/field_picker.tsx b/x-pack/plugins/lens/public/shared_components/field_picker/field_picker.tsx index bde920446d4684..eb33bb41e03730 100644 --- a/x-pack/plugins/lens/public/shared_components/field_picker/field_picker.tsx +++ b/x-pack/plugins/lens/public/shared_components/field_picker/field_picker.tsx @@ -30,7 +30,7 @@ const DEFAULT_COMBOBOX_WIDTH = 305; const COMBOBOX_PADDINGS = 90; const DEFAULT_FONT = '14px Inter'; -export function FieldPicker({ +export function FieldPicker({ selectedOptions, options, onChoose, diff --git a/x-pack/plugins/lens/public/shared_components/index.ts b/x-pack/plugins/lens/public/shared_components/index.ts index e3a9af00ad0055..c22f071ceede3e 100644 --- a/x-pack/plugins/lens/public/shared_components/index.ts +++ b/x-pack/plugins/lens/public/shared_components/index.ts @@ -11,6 +11,7 @@ export { LegendSettingsPopover } from './legend_settings_popover'; export { PalettePicker } from './palette_picker'; export { FieldPicker, LensFieldIcon, TruncatedLabel } from './field_picker'; export type { FieldOption, FieldOptionValue } from './field_picker'; +export { ChangeIndexPattern, fieldExists, fieldContainsData } from './dataview_picker'; export { RangeInputField } from './range_input_field'; export { BucketAxisBoundsControl, diff --git a/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap b/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap index 7f70508dc423ff..a6759521f562e7 100644 --- a/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap +++ b/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap @@ -4,6 +4,12 @@ exports[`Initializing the store should initialize all datasources with state fro Object { "lens": Object { "activeDatasourceId": "testDatasource", + "dataViews": Object { + "existingFields": Object {}, + "indexPatternRefs": Array [], + "indexPatterns": Object {}, + "isFirstExistenceFetch": true, + }, "datasourceStates": Object { "testDatasource": Object { "isLoading": false, diff --git a/x-pack/plugins/lens/public/state_management/context_middleware/index.ts b/x-pack/plugins/lens/public/state_management/context_middleware/index.ts index 90cd4ba27723eb..7d1e6a0b48fbae 100644 --- a/x-pack/plugins/lens/public/state_management/context_middleware/index.ts +++ b/x-pack/plugins/lens/public/state_management/context_middleware/index.ts @@ -23,11 +23,14 @@ import { onActiveDataChange } from '../lens_slice'; import { DatasourceMap } from '../../types'; function isTimeBased(state: LensState, datasourceMap: DatasourceMap) { - const { activeDatasourceId, datasourceStates } = state.lens; + const { activeDatasourceId, datasourceStates, dataViews } = state.lens; return Boolean( activeDatasourceId && datasourceStates[activeDatasourceId] && - datasourceMap[activeDatasourceId].isTimeBased?.(datasourceStates[activeDatasourceId].state) + datasourceMap[activeDatasourceId].isTimeBased?.( + datasourceStates[activeDatasourceId].state, + dataViews.indexPatterns + ) ); } diff --git a/x-pack/plugins/lens/public/state_management/index.ts b/x-pack/plugins/lens/public/state_management/index.ts index 7b9c345ff89f63..e41247557aa0af 100644 --- a/x-pack/plugins/lens/public/state_management/index.ts +++ b/x-pack/plugins/lens/public/state_management/index.ts @@ -33,6 +33,7 @@ export const { rollbackSuggestion, submitSuggestion, switchDatasource, + updateIndexPatterns, setToggleFullscreen, initEmpty, editVisualizationAction, diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts index e25c57ac129c9b..5ee4c82d7ce5fd 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts @@ -12,8 +12,8 @@ import { setState, initEmpty, LensStoreDeps } from '..'; import { disableAutoApply, getPreloadedState } from '../lens_slice'; import { SharingSavedObjectProps } from '../../types'; import { LensEmbeddableInput, LensByReferenceInput } from '../../embeddable/embeddable'; -import { getInitialDatasourceId } from '../../utils'; -import { initializeDatasources } from '../../editor_frame_service/editor_frame'; +import { getInitialDatasourceId, getInitialDataViewsObject } from '../../utils'; +import { initializeSources } from '../../editor_frame_service/editor_frame'; import { LensAppServices } from '../../app_plugin/types'; import { getEditPath, getFullPath, LENS_EMBEDDABLE_TYPE } from '../../../common/constants'; import { Document } from '../../persistence'; @@ -102,21 +102,37 @@ export function loadInitial( getPreloadedState(storeDeps); const { attributeService, notifications, data, dashboardFeatureFlag } = lensServices; const { lens } = store.getState(); + + const loaderSharedArgs = { + dataViews: lensServices.dataViews, + storage: lensServices.storage, + defaultIndexPatternId: lensServices.uiSettings.get('defaultIndex'), + }; + if ( !initialInput || (attributeService.inputIsRefType(initialInput) && initialInput.savedObjectId === lens.persistedDoc?.savedObjectId) ) { - return initializeDatasources(datasourceMap, lens.datasourceStates, undefined, initialContext, { - isFullEditor: true, - }) - .then((result) => { + return initializeSources( + { + datasourceMap, + datasourceStates: lens.datasourceStates, + initialContext, + ...loaderSharedArgs, + }, + { + isFullEditor: true, + } + ) + .then(({ states, indexPatterns, indexPatternRefs }) => { store.dispatch( initEmpty({ newState: { ...emptyState, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), searchSessionId: data.search.session.getSessionId() || data.search.session.start(), - datasourceStates: Object.entries(result).reduce( + datasourceStates: Object.entries(states).reduce( (state, [datasourceId, datasourceState]) => ({ ...state, [datasourceId]: { @@ -143,7 +159,7 @@ export function loadInitial( }); } - getPersisted({ initialInput, lensServices, history }) + return getPersisted({ initialInput, lensServices, history }) .then( (persisted) => { if (persisted) { @@ -170,17 +186,19 @@ export function loadInitial( const filters = data.query.filterManager.inject(doc.state.filters, doc.references); // Don't overwrite any pinned filters data.query.filterManager.setAppFilters(filters); - - initializeDatasources( - datasourceMap, - docDatasourceStates, - doc.references, - initialContext, + return initializeSources( { - isFullEditor: true, - } + datasourceMap, + datasourceStates: docDatasourceStates, + references: doc.references, + initialContext, + dataViews: lensServices.dataViews, + storage: lensServices.storage, + defaultIndexPatternId: lensServices.uiSettings.get('defaultIndex'), + }, + { isFullEditor: true } ) - .then((result) => { + .then(({ states, indexPatterns, indexPatternRefs }) => { const currentSessionId = data.search.session.getSessionId(); store.dispatch( setState({ @@ -201,7 +219,8 @@ export function loadInitial( activeId: doc.visualizationType, state: doc.state.visualization, }, - datasourceStates: Object.entries(result).reduce( + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + datasourceStates: Object.entries(states).reduce( (state, [datasourceId, datasourceState]) => ({ ...state, [datasourceId]: { diff --git a/x-pack/plugins/lens/public/state_management/lens_slice.ts b/x-pack/plugins/lens/public/state_management/lens_slice.ts index 14510a47b9d1da..b880b9478c16a4 100644 --- a/x-pack/plugins/lens/public/state_management/lens_slice.ts +++ b/x-pack/plugins/lens/public/state_management/lens_slice.ts @@ -14,13 +14,13 @@ import { LensEmbeddableInput } from '..'; import { TableInspectorAdapter } from '../editor_frame_service/types'; import type { VisualizeEditorContext, Suggestion } from '../types'; import { getInitialDatasourceId, getResolvedDateRange, getRemoveOperation } from '../utils'; -import { LensAppState, LensStoreDeps, VisualizationState } from './types'; -import { Datasource, Visualization } from '../types'; +import type { DataViewsState, LensAppState, LensStoreDeps, VisualizationState } from './types'; +import type { Datasource, Visualization } from '../types'; import { generateId } from '../id_generator'; import type { LayerType } from '../../common/types'; import { getLayerType } from '../editor_frame_service/editor_frame/config_panel/add_layer'; import { getVisualizeFieldSuggestions } from '../editor_frame_service/editor_frame/suggestion_helpers'; -import { FramePublicAPI, LensEditContextMapping, LensEditEvent } from '../types'; +import type { FramePublicAPI, LensEditContextMapping, LensEditEvent } from '../types'; import { selectFramePublicAPI } from './selectors'; export const initialState: LensAppState = { @@ -39,6 +39,12 @@ export const initialState: LensAppState = { state: null, activeId: null, }, + dataViews: { + indexPatternRefs: [], + indexPatterns: {}, + existingFields: {}, + isFirstExistenceFetch: true, + }, }; export const getPreloadedState = ({ @@ -74,7 +80,7 @@ export const getPreloadedState = ({ activeDatasourceId: initialDatasourceId, datasourceStates, visualization: { - state: null as unknown, + state: null, activeId: Object.keys(visualizationMap)[0] || null, }, }; @@ -163,6 +169,17 @@ export const setLayerDefaultDimension = createAction<{ groupId: string; }>('lens/setLayerDefaultDimension'); +export const updateIndexPatterns = createAction>( + 'lens/updateIndexPatterns' +); +export const changeIndexPattern = createAction<{ + visualizationIds?: string[]; + datasourceIds?: string[]; + indexPatternId: string; + layerId?: string; + dataViews: Partial; +}>('lens/changeIndexPattern'); + export const lensActions = { setState, onActiveDataChange, @@ -188,6 +205,8 @@ export const lensActions = { removeOrClearLayer, addLayer, setLayerDefaultDimension, + updateIndexPatterns, + changeIndexPattern, }; export const makeLensReducer = (storeDeps: LensStoreDeps) => { @@ -282,6 +301,107 @@ export const makeLensReducer = (storeDeps: LensStoreDeps) => { ? activeVisualization.clearLayer(state.visualization.state, layerId) : activeVisualization.removeLayer(state.visualization.state, layerId); }, + [changeIndexPattern.type]: ( + state, + { + payload, + }: { + payload: { + visualizationIds?: string; + datasourceIds?: string; + layerId?: string; + indexPatternId: string; + dataViews: Pick; + }; + } + ) => { + const { visualizationIds, datasourceIds, layerId, indexPatternId, dataViews } = payload; + const newState: Partial = { dataViews: { ...state.dataViews, ...dataViews } }; + if (visualizationIds?.length) { + for (const visualizationId of visualizationIds) { + const activeVisualization = + visualizationId && + state.visualization.activeId !== visualizationId && + visualizationMap[visualizationId]; + if (activeVisualization && layerId && activeVisualization?.onIndexPatternChange) { + newState.visualization = { + ...state.visualization, + state: activeVisualization.onIndexPatternChange( + state.visualization.state, + layerId, + indexPatternId + ), + }; + } + } + } + if (datasourceIds?.length) { + newState.datasourceStates = { ...state.datasourceStates }; + const frame = selectFramePublicAPI( + { lens: { ...current(state), dataViews: newState.dataViews! } }, + datasourceMap + ); + const datasourceLayers = frame.datasourceLayers; + + for (const datasourceId of datasourceIds) { + const activeDatasource = datasourceId && datasourceMap[datasourceId]; + if (activeDatasource && activeDatasource?.onIndexPatternChange) { + newState.datasourceStates = { + ...newState.datasourceStates, + [datasourceId]: { + isLoading: false, + state: activeDatasource.onIndexPatternChange( + newState.datasourceStates[datasourceId].state, + dataViews.indexPatterns, + indexPatternId, + layerId + ), + }, + }; + // Update the visualization columns + if (layerId && state.visualization.activeId) { + const nextPublicAPI = activeDatasource.getPublicAPI({ + state: newState.datasourceStates[datasourceId].state, + layerId, + indexPatterns: dataViews.indexPatterns, + }); + const nextTable = new Set( + nextPublicAPI.getTableSpec().map(({ columnId }) => columnId) + ); + const datasourcePublicAPI = datasourceLayers[layerId]; + if (datasourcePublicAPI) { + const removed = datasourcePublicAPI + .getTableSpec() + .map(({ columnId }) => columnId) + .filter((columnId) => !nextTable.has(columnId)); + const activeVisualization = visualizationMap[state.visualization.activeId]; + let nextVisState = (newState.visualization || state.visualization).state; + removed.forEach((columnId) => { + nextVisState = activeVisualization.removeDimension({ + layerId, + columnId, + prevState: nextVisState, + frame, + }); + }); + newState.visualization = { + ...state.visualization, + state: nextVisState, + }; + } + } + } + } + } + + return { ...state, ...newState }; + }, + [updateIndexPatterns.type]: (state, { payload }: { payload: Partial }) => { + return { + ...state, + dataViews: { ...state.dataViews, ...payload }, + }; + }, [updateDatasourceState.type]: ( state, { @@ -449,6 +569,7 @@ export const makeLensReducer = (storeDeps: LensStoreDeps) => { datasourceStates: newState.datasourceStates, visualizationMap, visualizeTriggerFieldContext: payload.initialContext, + dataViews: newState.dataViews, }); if (suggestion) { return { @@ -737,10 +858,15 @@ function addInitialValueIfAvailable({ if (!noDatasource && activeDatasource?.initializeDimension) { return { - activeDatasourceState: activeDatasource.initializeDimension(datasourceState, layerId, { - ...info, - columnId: columnId || info.columnId, - }), + activeDatasourceState: activeDatasource.initializeDimension( + datasourceState, + layerId, + framePublicAPI.dataViews.indexPatterns, + { + ...info, + columnId: columnId || info.columnId, + } + ), activeVisualizationState, }; } else { diff --git a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx index 9ae27a9c0073e1..2d8ce9405f12ff 100644 --- a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx +++ b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx @@ -120,17 +120,15 @@ describe('Initializing the store', () => { datasource1State, [], undefined, - { - isFullEditor: true, - } + [], + {} ); expect(datasourceMap.testDatasource2.initialize).toHaveBeenCalledWith( datasource2State, [], undefined, - { - isFullEditor: true, - } + [], + {} ); expect(datasourceMap.testDatasource3.initialize).not.toHaveBeenCalled(); expect(store.getState()).toMatchSnapshot(); diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts index 9217c66863c5c9..f1f53197978fa9 100644 --- a/x-pack/plugins/lens/public/state_management/selectors.ts +++ b/x-pack/plugins/lens/public/state_management/selectors.ts @@ -27,6 +27,7 @@ export const selectChangesApplied = (state: LensState) => export const selectDatasourceStates = (state: LensState) => state.lens.datasourceStates; export const selectActiveDatasourceId = (state: LensState) => state.lens.activeDatasourceId; export const selectActiveData = (state: LensState) => state.lens.activeData; +export const selectDataViews = (state: LensState) => state.lens.dataViews; export const selectIsFullscreenDatasource = (state: LensState) => Boolean(state.lens.isFullscreenDatasource); @@ -155,8 +156,10 @@ export const selectDatasourceLayers = createSelector( [ selectDatasourceStates, selectInjectedDependencies as SelectInjectedDependenciesFunction, + selectDataViews, ], - (datasourceStates, datasourceMap) => getDatasourceLayers(datasourceStates, datasourceMap) + (datasourceStates, datasourceMap, dataViews) => + getDatasourceLayers(datasourceStates, datasourceMap, dataViews.indexPatterns) ); export const selectFramePublicAPI = createSelector( @@ -165,12 +168,18 @@ export const selectFramePublicAPI = createSelector( selectActiveData, selectInjectedDependencies as SelectInjectedDependenciesFunction, selectResolvedDateRange, + selectDataViews, ], - (datasourceStates, activeData, datasourceMap, dateRange) => { + (datasourceStates, activeData, datasourceMap, dateRange, dataViews) => { return { - datasourceLayers: getDatasourceLayers(datasourceStates, datasourceMap), + datasourceLayers: getDatasourceLayers( + datasourceStates, + datasourceMap, + dataViews.indexPatterns + ), activeData, dateRange, + dataViews, }; } ); diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts index 4c6f4adc59ff5d..7b461338261fc6 100644 --- a/x-pack/plugins/lens/public/state_management/types.ts +++ b/x-pack/plugins/lens/public/state_management/types.ts @@ -11,7 +11,7 @@ import { Filter, Query } from '@kbn/es-query'; import { SavedQuery } from '@kbn/data-plugin/public'; import { Document } from '../persistence'; -import { TableInspectorAdapter } from '../editor_frame_service/types'; +import type { TableInspectorAdapter } from '../editor_frame_service/types'; import { DateRange } from '../../common'; import { LensAppServices } from '../app_plugin/types'; import { @@ -19,13 +19,24 @@ import { VisualizationMap, SharingSavedObjectProps, VisualizeEditorContext, + IndexPattern, + IndexPatternRef, } from '../types'; export interface VisualizationState { activeId: string | null; state: unknown; } -export type DatasourceStates = Record; +export interface DataViewsState { + indexPatternRefs: IndexPatternRef[]; + indexPatterns: Record; + existingFields: Record>; + isFirstExistenceFetch: boolean; + existenceFetchFailed?: boolean; + existenceFetchTimeout?: boolean; +} + +export type DatasourceStates = Record; export interface PreviewState { visualization: VisualizationState; datasourceStates: DatasourceStates; @@ -53,6 +64,8 @@ export interface LensAppState extends EditorFrameState { searchSessionId: string; resolvedDateRange: DateRange; sharingSavedObjectProps?: Omit; + // Dataview/Indexpattern management has moved in here from datasource + dataViews: DataViewsState; } export type DispatchSetState = (state: Partial) => { diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 99ef0458c84db9..0a76ceec5d3153 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -4,13 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { Ast } from '@kbn/interpreter'; +import type { Ast } from '@kbn/interpreter'; import type { IconType } from '@elastic/eui/src/components/icon/icon'; import type { CoreSetup, SavedObjectReference, ResolvedSimpleSavedObject } from '@kbn/core/public'; import type { PaletteOutput } from '@kbn/coloring'; import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; import type { MutableRefObject } from 'react'; -import { Filter, TimeRange } from '@kbn/es-query'; +import type { Filter, TimeRange } from '@kbn/es-query'; import type { ExpressionAstExpression, ExpressionRendererEvent, @@ -24,8 +24,11 @@ import type { RowClickContext, VisualizeFieldContext, } from '@kbn/ui-actions-plugin/public'; -import { ClickTriggerEvent, BrushTriggerEvent } from '@kbn/charts-plugin/public'; -import { DraggingIdentifier, DragDropIdentifier, DragContextState } from './drag_drop'; +import type { ClickTriggerEvent, BrushTriggerEvent } from '@kbn/charts-plugin/public'; +import type { IndexPatternAggRestrictions } from '@kbn/data-plugin/public'; +import type { FieldSpec } from '@kbn/data-views-plugin/common'; +import type { FieldFormatParams } from '@kbn/field-formats-plugin/common'; +import type { DraggingIdentifier, DragDropIdentifier, DragContextState } from './drag_drop'; import type { DateRange, LayerType, SortingHint } from '../common'; import type { LensSortActionData, @@ -41,21 +44,57 @@ import { LENS_EDIT_PAGESIZE_ACTION, } from './visualizations/datatable/components/constants'; import type { LensInspector } from './lens_inspector_service'; +import { DataViewsState } from './state_management/types'; +import { IndexPatternServiceAPI } from './indexpattern_service/service'; + +export interface IndexPatternRef { + id: string; + title: string; + name?: string; +} + +export interface IndexPattern { + id: string; + fields: IndexPatternField[]; + getFieldByName(name: string): IndexPatternField | undefined; + title: string; + name?: string; + timeFieldName?: string; + fieldFormatMap?: Record< + string, + { + id: string; + params: FieldFormatParams; + } + >; + hasRestrictions: boolean; +} + +export type IndexPatternField = FieldSpec & { + displayName: string; + aggregationRestrictions?: Partial; + meta?: boolean; + runtime?: boolean; +}; export type ErrorCallback = (e: { message: string }) => void; export interface PublicAPIProps { state: T; layerId: string; + indexPatterns: IndexPatternMap; } export interface EditorFrameProps { showNoDataPopover: () => void; lensInspector: LensInspector; + indexPatternService: IndexPatternServiceAPI; } export type VisualizationMap = Record; export type DatasourceMap = Record; +export type IndexPatternMap = Record; +export type ExistingFieldsMap = Record>; export interface EditorFrameInstance { EditorFrameContainer: (props: EditorFrameProps) => React.ReactElement; @@ -206,6 +245,7 @@ export interface GetDropPropsArgs { prioritizedOperation?: string; isNewColumn?: boolean; }; + indexPatterns: IndexPatternMap; } /** @@ -221,8 +261,9 @@ export interface Datasource { state?: P, savedObjectReferences?: SavedObjectReference[], initialContext?: VisualizeFieldContext | VisualizeEditorContext, - options?: InitializationOptions - ) => Promise; + indexPatternRefs?: IndexPatternRef[], + indexPatterns?: IndexPatternMap + ) => T; // Given the current state, which parts should be saved? getPersistableState: (state: T) => { state: P; savedObjectReferences: SavedObjectReference[] }; @@ -232,10 +273,16 @@ export interface Datasource { removeLayer: (state: T, layerId: string) => T; clearLayer: (state: T, layerId: string) => T; getLayers: (state: T) => string[]; - removeColumn: (props: { prevState: T; layerId: string; columnId: string }) => T; + removeColumn: (props: { + prevState: T; + layerId: string; + columnId: string; + indexPatterns: IndexPatternMap; + }) => T; initializeDimension?: ( state: T, layerId: string, + indexPatterns: IndexPatternMap, value: { columnId: string; groupId: string; @@ -283,33 +330,50 @@ export interface Datasource { state: T; setState: StateSetter; }) => void; + onIndexPatternChange?: ( + state: T, + indexPatterns: IndexPatternMap, + indexPatternId: string, + layerId?: string + ) => T; - refreshIndexPatternsList?: (props: { indexPatternId: string; setState: StateSetter }) => void; + onRefreshIndexPattern: () => void; - toExpression: (state: T, layerId: string) => ExpressionAstExpression | string | null; + toExpression: ( + state: T, + layerId: string, + indexPatterns: IndexPatternMap + ) => ExpressionAstExpression | string | null; getDatasourceSuggestionsForField: ( state: T, field: unknown, - filterFn: (layerId: string) => boolean + filterFn: (layerId: string) => boolean, + indexPatterns: IndexPatternMap ) => Array>; getDatasourceSuggestionsForVisualizeCharts: ( state: T, - context: VisualizeEditorLayersContext[] + context: VisualizeEditorLayersContext[], + indexPatterns: IndexPatternMap ) => Array>; getDatasourceSuggestionsForVisualizeField: ( state: T, indexPatternId: string, - fieldName: string + fieldName: string, + indexPatterns: IndexPatternMap ) => Array>; getDatasourceSuggestionsFromCurrentState: ( state: T, + indexPatterns: IndexPatternMap, filterFn?: (layerId: string) => boolean, activeData?: Record ) => Array>; getPublicAPI: (props: PublicAPIProps) => DatasourcePublicAPI; - getErrorMessages: (state: T) => + getErrorMessages: ( + state: T, + indexPatterns: Record + ) => | Array<{ shortMessage: string; longMessage: React.ReactNode; @@ -323,7 +387,7 @@ export interface Datasource { /** * Check the internal state integrity and returns a list of missing references */ - checkIntegrity: (state: T) => string[]; + checkIntegrity: (state: T, indexPatterns: IndexPatternMap) => string[]; /** * The frame calls this function to display warnings about visualization */ @@ -335,11 +399,16 @@ export interface Datasource { /** * Checks if the visualization created is time based, for example date histogram */ - isTimeBased: (state: T) => boolean; + isTimeBased: (state: T, indexPatterns: IndexPatternMap) => boolean; /** * Given the current state layer and a columnId will verify if the column configuration has errors */ - isValidColumn: (state: T, layerId: string, columnId: string) => boolean; + isValidColumn: ( + state: T, + indexPatterns: IndexPatternMap, + layerId: string, + columnId: string + ) => boolean; /** * Are these datasources equivalent? */ @@ -414,7 +483,10 @@ export interface DatasourceDataPanelProps { filters: Filter[]; dropOntoWorkspace: (field: DragDropIdentifier) => void; hasSuggestionForField: (field: DragDropIdentifier) => boolean; + onChangeIndexPattern: (indexPatternId: string, datasourceId: string, layerId?: string) => void; uiActions: UiActionsStart; + indexPatternService: IndexPatternServiceAPI; + frame: FramePublicAPI; } interface SharedDimensionProps { @@ -437,6 +509,8 @@ export type DatasourceDimensionProps = SharedDimensionProps & { onRemove?: (accessor: string) => void; state: T; activeData?: Record; + indexPatterns: IndexPatternMap; + existingFields: Record>; hideTooltip?: boolean; invalid?: boolean; invalidMessage?: string; @@ -472,8 +546,9 @@ export type DatasourceDimensionTriggerProps = DatasourceDimensionProps; export interface DatasourceLayerPanelProps { layerId: string; state: T; - setState: StateSetter; activeData?: Record; + dataViews: DataViewsState; + onChangeIndexPattern: (indexPatternId: string, datasourceId: string, layerId?: string) => void; } export interface DragDropOperation { @@ -507,6 +582,7 @@ export interface DatasourceDimensionDropProps { export type DatasourceDimensionDropHandlerProps = DatasourceDimensionDropProps & { source: DragDropIdentifier; dropType: DropType; + indexPatterns: IndexPatternMap; }; export type FieldOnlyDataType = @@ -563,6 +639,11 @@ export interface VisualizationConfigProps { export type VisualizationLayerWidgetProps = VisualizationConfigProps & { setState: (newState: T) => void; + onChangeIndexPattern: (indexPatternId: string, layerId: string) => void; +}; + +export type VisualizationLayerHeaderContentProps = VisualizationLayerWidgetProps & { + defaultIndexPatternId: string; }; export interface VisualizationToolbarProps { @@ -729,6 +810,7 @@ export interface FramePublicAPI { * If accessing, make sure to check whether expected columns actually exist. */ activeData?: Record; + dataViews: DataViewsState; } export interface FrameDatasourceAPI extends FramePublicAPI { @@ -849,13 +931,22 @@ export interface Visualization { }; /** - * Header rendered as layer title This can be used for both static and dynamic content lioke + * Header rendered as layer title. This can be used for both static and dynamic content like * for extra configurability, such as for switch chart type */ renderLayerHeader?: ( domElement: Element, props: VisualizationLayerWidgetProps ) => ((cleanupElement: Element) => void) | void; + + /** + * Layer panel content rendered. This can be used to render a custom content below the title, + * like a custom dataview switch + */ + renderLayerPanel?: ( + domElement: Element, + props: VisualizationLayerWidgetProps + ) => ((cleanupElement: Element) => void) | void; /** * Toolbar rendered above the visualization. This is meant to be used to provide chart-level * settings for the visualization. @@ -981,6 +1072,11 @@ export interface Visualization { */ onEditAction?: (state: T, event: LensEditEvent) => T; + /** + * Some visualization track indexPattern changes (i.e. annotations) + * This method makes it aware of the change and produces a new updated state + */ + onIndexPatternChange?: (state: T, indexPatternId: string, layerId?: string) => T; /** * Gets custom display options for showing the visualization. */ diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 4b0f24ce058356..e5995762b55055 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -14,8 +14,15 @@ import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public' import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { BrushTriggerEvent, ClickTriggerEvent } from '@kbn/charts-plugin/public'; import type { Document } from './persistence/saved_object_store'; -import type { Datasource, DatasourceMap, Visualization, StateSetter } from './types'; +import type { + Datasource, + DatasourceMap, + Visualization, + IndexPatternMap, + IndexPatternRef, +} from './types'; import type { DatasourceStates, VisualizationState } from './state_management'; +import { IndexPatternServiceAPI } from './indexpattern_service/service'; export function getVisualizeGeoFieldMessage(fieldType: string) { return i18n.translate('xpack.lens.visualizeGeoFieldMessage', { @@ -58,40 +65,52 @@ export const getInitialDatasourceId = (datasourceMap: DatasourceMap, doc?: Docum return (doc && getActiveDatasourceIdFromDoc(doc)) || Object.keys(datasourceMap)[0] || null; }; -export function handleIndexPatternChange({ - activeDatasources, - datasourceStates, - indexPatternId, - setDatasourceState, -}: { - activeDatasources: Record; - datasourceStates: DatasourceStates; - indexPatternId: string; - setDatasourceState: StateSetter; -}): void { - Object.entries(activeDatasources).forEach(([id, datasource]) => { - datasource?.updateCurrentIndexPatternId?.({ - state: datasourceStates[id].state, - indexPatternId, - setState: setDatasourceState, - }); - }); +export function getInitialDataViewsObject( + indexPatterns: IndexPatternMap, + indexPatternRefs: IndexPatternRef[] +) { + return { + indexPatterns, + indexPatternRefs, + existingFields: {}, + isFirstExistenceFetch: true, + }; } -export function refreshIndexPatternsList({ +export async function refreshIndexPatternsList({ activeDatasources, + indexPatternService, indexPatternId, - setDatasourceState, + indexPatternsCache, }: { + indexPatternService: IndexPatternServiceAPI; activeDatasources: Record; indexPatternId: string; - setDatasourceState: StateSetter; -}): void { - Object.entries(activeDatasources).forEach(([id, datasource]) => { - datasource?.refreshIndexPatternsList?.({ - indexPatternId, - setState: setDatasourceState, - }); + indexPatternsCache: IndexPatternMap; +}) { + // collect all the onRefreshIndex callbacks from datasources + const onRefreshCallbacks = Object.values(activeDatasources) + .map((datasource) => datasource?.onRefreshIndexPattern) + .filter(Boolean); + + const [newlyMappedIndexPattern, indexPatternRefs] = await Promise.all([ + indexPatternService.loadIndexPatterns({ + cache: {}, + patterns: [indexPatternId], + onIndexPatternRefresh: () => onRefreshCallbacks.forEach((fn) => fn()), + }), + indexPatternService.loadIndexPatternRefs({ isFullEditor: true }), + ]); + const indexPattern = newlyMappedIndexPattern[indexPatternId]; + // But what about existingFields here? + // When the indexPatterns cache object gets updated, the data panel will + // notice it and refetch the fields list existence map + indexPatternService.updateDataViewsState({ + indexPatterns: { + ...indexPatternsCache, + [indexPatternId]: indexPattern, + }, + indexPatternRefs, }); } @@ -121,9 +140,9 @@ export function getIndexPatternsIds({ export async function getIndexPatternsObjects( ids: string[], - indexPatternsService: DataViewsContract + dataViews: DataViewsContract ): Promise<{ indexPatterns: DataView[]; rejectedIds: string[] }> { - const responses = await Promise.allSettled(ids.map((id) => indexPatternsService.get(id))); + const responses = await Promise.allSettled(ids.map((id) => dataViews.get(id))); const fullfilled = responses.filter( (response): response is PromiseFulfilledResult => response.status === 'fulfilled' ); diff --git a/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.test.ts b/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.test.ts index 1f923f85ee1be5..8560e3bbaec311 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.test.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.test.ts @@ -8,9 +8,15 @@ import { FramePublicAPI } from '../../../types'; import { getStaticDate } from './helpers'; -const frame = { +const frame: FramePublicAPI = { datasourceLayers: {}, dateRange: { fromDate: '2022-02-01T00:00:00.000Z', toDate: '2022-04-20T00:00:00.000Z' }, + dataViews: { + indexPatterns: {}, + indexPatternRefs: [], + existingFields: {}, + isFirstExistenceFetch: true, + }, }; describe('annotations helpers', () => { diff --git a/x-pack/plugins/lens/public/visualizations/xy/index.ts b/x-pack/plugins/lens/public/visualizations/xy/index.ts index 88a3a4a4ce0483..37d4f46a5bcc72 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/index.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/index.ts @@ -6,6 +6,7 @@ */ import type { CoreSetup } from '@kbn/core/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import { EventAnnotationPluginSetup } from '@kbn/event-annotation-plugin/public'; import type { ExpressionsSetup } from '@kbn/expressions-plugin/public'; import type { ChartsPluginSetup } from '@kbn/charts-plugin/public'; @@ -29,12 +30,15 @@ export class XyVisualization { ) { editorFrame.registerVisualization(async () => { const { getXyVisualization } = await import('../../async_services'); - const [, { charts, data, fieldFormats, eventAnnotation }] = await core.getStartServices(); + const [coreStart, { charts, data, fieldFormats, eventAnnotation }] = + await core.getStartServices(); const palettes = await charts.palettes.getPalettes(); const eventAnnotationService = await eventAnnotation.getService(); const useLegacyTimeAxis = core.uiSettings.get(LEGACY_TIME_AXIS); return getXyVisualization({ - datatableUtilities: data.datatableUtilities, + core: coreStart, + data, + storage: new Storage(localStorage), paletteService: palettes, eventAnnotationService, fieldFormats, diff --git a/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts b/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts index 02b36d6b27c4f5..11215a8cf492c2 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/to_expression.test.ts @@ -8,7 +8,6 @@ import { Ast, fromExpression } from '@kbn/interpreter'; import { Position } from '@elastic/charts'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; -import { createDatatableUtilitiesMock } from '@kbn/data-plugin/common/mocks'; import { getXyVisualization } from './xy_visualization'; import { OperationDescriptor } from '../../types'; import { createMockDatasource, createMockFramePublicAPI } from '../../mocks'; @@ -16,17 +15,21 @@ import { layerTypes } from '../../../common'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import { eventAnnotationServiceMock } from '@kbn/event-annotation-plugin/public/mocks'; import { defaultReferenceLineColor } from './color_assignment'; -import { themeServiceMock } from '@kbn/core/public/mocks'; +import { coreMock, themeServiceMock } from '@kbn/core/public/mocks'; import { LegendSize } from '@kbn/visualizations-plugin/common'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; describe('#toExpression', () => { const xyVisualization = getXyVisualization({ - datatableUtilities: createDatatableUtilitiesMock(), paletteService: chartPluginMock.createPaletteRegistry(), fieldFormats: fieldFormatsServiceMock.createStartContract(), kibanaTheme: themeServiceMock.createStartContract(), useLegacyTimeAxis: false, eventAnnotationService: eventAnnotationServiceMock, + core: coreMock.createStart(), + storage: {} as IStorageWrapper, + data: dataPluginMock.createStartContract(), }); let mockDatasource: ReturnType; let frame: ReturnType; @@ -54,7 +57,8 @@ describe('#toExpression', () => { const datasourceExpression = mockDatasource.toExpression( frame.datasourceLayers.first, - 'first' + 'first', + frame.dataViews.indexPatterns ) ?? { type: 'expression', chain: [], diff --git a/x-pack/plugins/lens/public/visualizations/xy/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/xy/visualization.test.ts index 773132c56ce4b1..b1313d765ae926 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/visualization.test.ts @@ -23,7 +23,6 @@ import type { XYReferenceLineLayerConfig, SeriesType, } from './types'; -import { createDatatableUtilitiesMock } from '@kbn/data-plugin/common/mocks'; import { layerTypes } from '../../../common'; import { createMockDatasource, createMockFramePublicAPI } from '../../mocks'; import { LensIconChartBar } from '../../assets/chart_bar'; @@ -31,9 +30,11 @@ import type { VisualizeEditorLayersContext } from '@kbn/visualizations-plugin/pu import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import { Datatable } from '@kbn/expressions-plugin/common'; -import { themeServiceMock } from '@kbn/core/public/mocks'; +import { coreMock, themeServiceMock } from '@kbn/core/public/mocks'; import { eventAnnotationServiceMock } from '@kbn/event-annotation-plugin/public/mocks'; import { EventAnnotationConfig } from '@kbn/event-annotation-plugin/common'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; const exampleAnnotation: EventAnnotationConfig = { id: 'an1', @@ -75,12 +76,14 @@ const paletteServiceMock = chartPluginMock.createPaletteRegistry(); const fieldFormatsMock = fieldFormatsServiceMock.createStartContract(); const xyVisualization = getXyVisualization({ - datatableUtilities: createDatatableUtilitiesMock(), paletteService: paletteServiceMock, fieldFormats: fieldFormatsMock, useLegacyTimeAxis: false, kibanaTheme: themeServiceMock.createStartContract(), eventAnnotationService: eventAnnotationServiceMock, + core: coreMock.createStart(), + storage: {} as IStorageWrapper, + data: dataPluginMock.createStartContract(), }); describe('xy_visualization', () => { @@ -342,6 +345,7 @@ describe('xy_visualization', () => { ]); frame = { + ...frame, datasourceLayers: { first: mockDatasource.publicAPIMock, }, diff --git a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx index f5d241738dd4e2..e0d0a19cebec87 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/visualization.tsx @@ -11,13 +11,14 @@ import { Position } from '@elastic/charts'; import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import type { PaletteRegistry } from '@kbn/coloring'; -import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { ThemeServiceStart } from '@kbn/core/public'; +import { CoreStart, ThemeServiceStart } from '@kbn/core/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; import { FillStyle } from '@kbn/expression-xy-plugin/common'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { getSuggestions } from './xy_suggestions'; import { XyToolbar } from './xy_config_panel'; import { DimensionEditor } from './xy_config_panel/dimension_editor'; @@ -79,14 +80,18 @@ import { defaultAnnotationLabel } from './annotations/helpers'; import { onDropForVisualization } from '../../editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils'; export const getXyVisualization = ({ - datatableUtilities, + core, + storage, + data, paletteService, fieldFormats, useLegacyTimeAxis, kibanaTheme, eventAnnotationService, }: { - datatableUtilities: DatatableUtilitiesService; + core: CoreStart; + storage: IStorageWrapper; + data: DataPublicPluginStart; paletteService: PaletteRegistry; eventAnnotationService: EventAnnotationServiceType; fieldFormats: FieldFormatsStart; @@ -137,7 +142,10 @@ export const getXyVisualization = ({ layers: state.layers.map((l) => l.layerId !== layerId ? l - : newLayerState({ seriesType: state.preferredSeriesType, layerId }) + : newLayerState({ + seriesType: state.preferredSeriesType, + layerId, + }) ), }; }, @@ -189,6 +197,20 @@ export const getXyVisualization = ({ ]; }, + onIndexPatternChange(state, indexPatternId, layerId) { + const layerIndex = state.layers.findIndex((l) => l.layerId === layerId); + const layer = state.layers[layerIndex]; + if (!layer || !isAnnotationsLayer(layer)) { + return state; + } + const newLayers = [...state.layers]; + newLayers[layerIndex] = { ...layer }; + return { + ...state, + layers: newLayers, + }; + }, + getConfiguration({ state, frame, layerId }) { const layer = state.layers.find((l) => l.layerId === layerId); if (!layer) { @@ -520,7 +542,7 @@ export const getXyVisualization = ({ renderDimensionEditor(domElement, props) { const allProps = { ...props, - datatableUtilities, + datatableUtilities: data.datatableUtilities, formatFactory: fieldFormats.deserialize, paletteService, }; diff --git a/x-pack/plugins/lens/public/visualizations/xy/xy_suggestions.test.ts b/x-pack/plugins/lens/public/visualizations/xy/xy_suggestions.test.ts index 52039d68a9feec..676d1a0dafe294 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/xy_suggestions.test.ts +++ b/x-pack/plugins/lens/public/visualizations/xy/xy_suggestions.test.ts @@ -17,22 +17,25 @@ import { import { generateId } from '../../id_generator'; import { getXyVisualization } from './xy_visualization'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; -import { createDatatableUtilitiesMock } from '@kbn/data-plugin/common/mocks'; import { eventAnnotationServiceMock } from '@kbn/event-annotation-plugin/public/mocks'; import type { PaletteOutput } from '@kbn/coloring'; import { layerTypes } from '../../../common'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; -import { themeServiceMock } from '@kbn/core/public/mocks'; +import { coreMock, themeServiceMock } from '@kbn/core/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; jest.mock('../../id_generator'); const xyVisualization = getXyVisualization({ - datatableUtilities: createDatatableUtilitiesMock(), paletteService: chartPluginMock.createPaletteRegistry(), fieldFormats: fieldFormatsServiceMock.createStartContract(), useLegacyTimeAxis: false, kibanaTheme: themeServiceMock.createStartContract(), eventAnnotationService: eventAnnotationServiceMock, + core: coreMock.createStart(), + storage: {} as IStorageWrapper, + data: dataPluginMock.createStartContract(), }); describe('xy_suggestions', () => { From 0931bbe831f5098d1be2046e640549001ac0a162 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:02:47 +0100 Subject: [PATCH 48/59] [Security Solution][Detections] changes rules bulk edit modal title (#138077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Changes bulk edit confirmation modal window wordings: - update the modal title to `This action can only` instead of `The action will only` - Lowercase “custom rule” in the headline - Lowercase “machine learning” in the 2nd bullet - making the “c” in “custom” lowercase within the button in the bottom right. - remove `you’ve selected` at the end of the title - update the first sentence in the message body to `This action can't be applied to the following rules in your selection:` ### Before Screenshot 2022-08-04 at 08 35 49 ### After Screenshot 2022-08-10 at 11 30 04 --- .../integration/detection_rules/bulk_edit_rules.spec.ts | 2 +- .../cypress/integration/detection_rules/export_rule.spec.ts | 2 +- .../security_solution/cypress/tasks/rules_bulk_edit.ts | 4 ++-- .../all/bulk_actions/bulk_action_rule_errors_list.test.tsx | 4 ++-- .../rules/all/bulk_actions/bulk_action_rule_errors_list.tsx | 6 +++--- .../detections/pages/detection_engine/rules/translations.ts | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts index dd04d324d3739b..e787f4f58dc5c7 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/bulk_edit_rules.spec.ts @@ -130,7 +130,7 @@ describe('Detection rules, bulk edit', () => { // proceed with custom rule editing cy.get(MODAL_CONFIRMATION_BTN) - .should('have.text', `Edit ${expectedNumberOfCustomRulesToBeEdited} Custom rules`) + .should('have.text', `Edit ${expectedNumberOfCustomRulesToBeEdited} custom rules`) .click(); typeIndexPatterns([CUSTOM_INDEX_PATTERN_1]); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts index d48a2d847892a6..f844a2960deb38 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts @@ -78,7 +78,7 @@ describe('Export rules', () => { // proceed with exporting only custom rules cy.get(MODAL_CONFIRMATION_BTN) - .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} Custom rule`) + .should('have.text', `Export ${expectedNumberCustomRulesToBeExported} custom rule`) .click(); cy.get(TOASTER_BODY).should( diff --git a/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts b/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts index 611ec010d9d2fb..3c2ce5cdb439d9 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/rules_bulk_edit.ts @@ -85,13 +85,13 @@ export const checkElasticRulesCannotBeModified = (rulesCount: number) => { export const checkMachineLearningRulesCannotBeModified = (rulesCount: number) => { cy.get(MODAL_CONFIRMATION_BODY).contains( - `${rulesCount} custom Machine Learning rule (these rules don't have index patterns)` + `${rulesCount} custom machine learning rule (these rules don't have index patterns)` ); }; export const waitForMixedRulesBulkEditModal = (customRulesCount: number) => { cy.get(MODAL_CONFIRMATION_TITLE).should( 'have.text', - `The action will only be applied to ${customRulesCount} Custom rules you've selected` + `This action can only be applied to ${customRulesCount} custom rules` ); }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx index 2a14f5ca8b7c2e..82b78c319c0563 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.test.tsx @@ -61,11 +61,11 @@ describe('Component BulkEditRuleErrorsList', () => { ], [ BulkActionsDryRunErrCode.MACHINE_LEARNING_INDEX_PATTERN, - "2 custom Machine Learning rules (these rules don't have index patterns)", + "2 custom machine learning rules (these rules don't have index patterns)", ], [ BulkActionsDryRunErrCode.MACHINE_LEARNING_AUTH, - "2 Machine Learning rules can't be edited (test failure)", + "2 machine learning rules can't be edited (test failure)", ], [undefined, "2 rules can't be edited (test failure)"], ])('should render correct message for "%s" errorCode', (errorCode, value) => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx index d5058536afdc5a..7f5b3ea3f74ee3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/bulk_actions/bulk_action_rule_errors_list.tsx @@ -41,7 +41,7 @@ const BulkEditRuleErrorItem = ({
  1. @@ -51,7 +51,7 @@ const BulkEditRuleErrorItem = ({
  2. @@ -115,7 +115,7 @@ const BulkActionRuleErrorsListComponent = ({ <>
      diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index b4f25d1b5ff2fd..a00ba2cf3c829c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -234,7 +234,7 @@ export const BULK_ACTION_CONFIRMATION_PARTLY_TITLE = (customRulesCount: number) { values: { customRulesCount }, defaultMessage: - "The action will only be applied to {customRulesCount, plural, =1 {# Custom rule} other {# Custom rules}} you've selected", + 'This action can only be applied to {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', } ); @@ -257,7 +257,7 @@ export const BULK_EDIT_CONFIRMATION_CONFIRM = (customRulesCount: number) => 'xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel', { values: { customRulesCount }, - defaultMessage: 'Edit {customRulesCount, plural, =1 {# Custom rule} other {# Custom rules}}', + defaultMessage: 'Edit {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', } ); @@ -267,7 +267,7 @@ export const BULK_EXPORT_CONFIRMATION_CONFIRM = (customRulesCount: number) => { values: { customRulesCount }, defaultMessage: - 'Export {customRulesCount, plural, =1 {# Custom rule} other {# Custom rules}}', + 'Export {customRulesCount, plural, =1 {# custom rule} other {# custom rules}}', } ); From ea882a546627780216b897cfcb40c39d2bdf6391 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Fri, 12 Aug 2022 14:09:24 +0200 Subject: [PATCH 49/59] support logstash datastream in standalone query (#138689) --- .../server/lib/standalone_clusters/has_standalone_clusters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts index 5abdb5a9a4ca02..195c74ce20f7ee 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts @@ -47,7 +47,7 @@ export async function hasStandaloneClusters(req: LegacyRequest, ccs: string) { }, { terms: { - 'data_stream.dataset': ['node', 'node_stats', 'stats', 'state'], + 'data_stream.dataset': ['logstash.node', 'logstash.node_stats'], }, }, ], From f2da8548a9cae3f1001b57aea94b737e0d074af9 Mon Sep 17 00:00:00 2001 From: Faisal Kanout Date: Fri, 12 Aug 2022 15:16:34 +0200 Subject: [PATCH 50/59] [ResponseOps][ActionableObservability] - Fix flaky test in rule details page (#138492) * Add waitFor to get ruleTypeIndex from the hook * Fix typo * Remove the skip from the test suite * Add loaders for useLoadRuleTypes hook --- .../application/hooks/use_load_rule_types.ts | 4 +-- .../components/rule_definition.tsx | 35 +++++++++++++------ .../observability/pages/rule_details_page.ts | 7 ++-- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types.ts index 950d29c886f1a7..7382f3fbd39f2f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_types.ts @@ -23,14 +23,13 @@ export function useLoadRuleTypes({ filteredRuleTypes }: RuleTypesProps) { const { http } = useKibana().services; const isMounted = useRef(false); const [ruleTypesState, setRuleTypesState] = useState({ - isLoading: false, + isLoading: true, data: [], error: null, }); const [ruleTypeIndex, setRuleTypeIndex] = useState(new Map()); async function fetchRuleTypes() { - setRuleTypesState({ ...ruleTypesState, isLoading: true }); try { const response = await loadRuleTypes({ http }); const index: RuleTypeIndex = new Map(); @@ -67,5 +66,6 @@ export function useLoadRuleTypes({ filteredRuleTypes }: RuleTypesProps) { ruleTypes: ruleTypesState.data, error: ruleTypesState.error, ruleTypeIndex, + ruleTypesIsLoading: ruleTypesState.isLoading, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.tsx index 39c5e549470c0c..1823e12090379e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_definition.tsx @@ -13,6 +13,7 @@ import { EuiFlexItem, EuiPanel, EuiTitle, + EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { formatDuration } from '@kbn/alerting-plugin/common'; @@ -38,7 +39,7 @@ export const RuleDefinition: React.FunctionComponent = ({ const [editFlyoutVisible, setEditFlyoutVisible] = useState(false); const [ruleType, setRuleType] = useState(); - const { ruleTypes, ruleTypeIndex } = useLoadRuleTypes({ + const { ruleTypes, ruleTypeIndex, ruleTypesIsLoading } = useLoadRuleTypes({ filteredRuleTypes, }); @@ -93,14 +94,20 @@ export const RuleDefinition: React.FunctionComponent = ({ })} - {hasEditButton && ( + {ruleTypesIsLoading ? ( - setEditFlyoutVisible(true)} - /> + + ) : ( + hasEditButton && ( + + setEditFlyoutVisible(true)} + /> + + ) )} @@ -114,10 +121,16 @@ export const RuleDefinition: React.FunctionComponent = ({ defaultMessage: 'Rule type', })} - + {ruleTypesIsLoading ? ( + + + + ) : ( + + )} diff --git a/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts b/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts index 88fdfb9e577714..d451de95fa9f87 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts @@ -35,8 +35,7 @@ export default ({ getService }: FtrProviderContext) => { return true; } - // FLAKY: https://github.com/elastic/kibana/issues/136000 - describe.skip('Observability Rule Details page', function () { + describe('Observability Rule Details page', function () { this.tags('includeFirefox'); let uptimeRuleId: string; @@ -133,6 +132,10 @@ export default ({ getService }: FtrProviderContext) => { }); it('maps correctly the rule type with the human readable rule type', async () => { + await retry.waitFor( + 'ruleTypeIndex to be loaded from hook', + async () => await testSubjects.exists('ruleSummaryRuleType') + ); const ruleType = await testSubjects.getVisibleText('ruleSummaryRuleType'); expect(ruleType).to.be('Log threshold'); }); From 554e83be1467d83cff80cf57aa13ccefb9f4fd1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Fri, 12 Aug 2022 15:47:20 +0200 Subject: [PATCH 51/59] [Synthtrace] Improve error message when APM package version is invalid (#138616) --- .../client/apm_synthtrace_kibana_client.ts | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts index 1dbd2ad40e7122..bf068d7f331857 100644 --- a/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts +++ b/packages/elastic-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts @@ -53,22 +53,20 @@ export class ApmSynthtraceKibanaClient { return kibanaUrl; }); } - async fetchLatestApmPackageVersion(version: string) { + async fetchLatestApmPackageVersion(currentKibanaVersion: string) { const url = 'https://epr-snapshot.elastic.co/search?package=apm&prerelease=true&all=true&kibana.version='; - const response = await fetch(url + version, { method: 'GET' }); - const json = await response.json(); - if (!Array.isArray(json)) { - throw new Error('Could not locate apm package compatible with the current kibana version'); - } - const versions = json - .map((item) => item.version) - .filter((v) => Semver.valid(v)) - .sort(Semver.rcompare); - if (versions.length === 0) { - throw new Error('Could not locate apm package compatible with the current kibana version'); + const response = await fetch(url + currentKibanaVersion, { method: 'GET' }); + const json = (await response.json()) as Array<{ version: string }>; + const packageVersions = (json ?? []).map((item) => item.version).sort(Semver.rcompare); + const validPackageVersions = packageVersions.filter((v) => Semver.valid(v)); + const bestMatch = validPackageVersions[0]; + if (!bestMatch) { + throw new Error( + `None of the available APM package versions matches the current Kibana version (${currentKibanaVersion}). The latest available version is ${packageVersions[0]}. This can happen if the Kibana version was recently bumped, and no matching APM package was released. Reach out to the fleet team if this persists.` + ); } - return versions[0]; + return bestMatch; } async installApmPackage(kibanaUrl: string, version: string, username: string, password: string) { From 61c6217a523850ace6c06d9c45e083d8229b7399 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Fri, 12 Aug 2022 06:49:16 -0700 Subject: [PATCH 52/59] [ML] Remove legend from screenshot creation for mapping anomalies (#137642) --- .../apps/ml_docs/anomaly_detection/mapping_anomalies.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts index 8e58a1db851826..01d0ccfe488c56 100644 --- a/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts +++ b/x-pack/test/screenshot_creation/apps/ml_docs/anomaly_detection/mapping_anomalies.ts @@ -12,7 +12,6 @@ import { LOGS_INDEX_PATTERN } from '..'; export default function ({ getPageObject, getService }: FtrProviderContext) { const header = getPageObject('header'); - const maps = getPageObject('maps'); const ml = getService('ml'); const mlScreenshots = getService('mlScreenshots'); const renderable = getService('renderable'); @@ -77,7 +76,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep('set maps options and take screenshot'); await ml.dataVisualizerTable.ensureDetailsOpen('geo.dest'); await renderable.waitForRender(); - await maps.openLegend(); await mlScreenshots.takeScreenshot( 'weblogs-data-visualizer-choropleth', @@ -121,7 +119,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await ml.testExecution.logTestStep('scroll map into view and take screenshot'); await ml.anomalyExplorer.scrollMapContainerIntoView(); await renderable.waitForRender(); - await maps.openLegend(); await mlScreenshots.takeScreenshot('weblogs-anomaly-explorer-vectors', screenshotDirectories); }); }); From 05b2659501f2c4972f35d638290340a3718df918 Mon Sep 17 00:00:00 2001 From: Najmieh Sadat <98463228+najmiehsa@users.noreply.github.com> Date: Fri, 12 Aug 2022 18:22:24 +0430 Subject: [PATCH 53/59] [Fleet]: updated wget command for Windows platform Fleet Server installation (#138638) * Edited the wget command for the windows platform * Updated the install command utils tests Co-authored-by: Kyle Pollich --- .../utils/install_command_utils.test.ts | 6 +++--- .../utils/install_command_utils.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts index f6b3b56c71adc1..ebe450bdfae8eb 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.test.ts @@ -52,7 +52,7 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' - wget https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip + Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip Expand-Archive .\\\\elastic-agent--windows-x86_64.zip cd elastic-agent--windows-x86_64 .\\\\elastic-agent.exe install \` @@ -169,7 +169,7 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' - wget https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip + Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip Expand-Archive .\\\\elastic-agent--windows-x86_64.zip cd elastic-agent--windows-x86_64 .\\\\elastic-agent.exe install \` @@ -283,7 +283,7 @@ describe('getInstallCommandForPlatform', () => { expect(res).toMatchInlineSnapshot(` "$ProgressPreference = 'SilentlyContinue' - wget https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip + Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent--windows-x86_64.zip -OutFile elastic-agent--windows-x86_64.zip Expand-Archive .\\\\elastic-agent--windows-x86_64.zip cd elastic-agent--windows-x86_64 .\\\\elastic-agent.exe install --url=http://fleetserver:8220 \` diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts index a7e867be73e09c..c5a58bef884f1c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/utils/install_command_utils.ts @@ -32,7 +32,7 @@ function getArtifact(platform: PLATFORM_TYPE, kibanaVersion: string) { windows: { downloadCommand: [ `$ProgressPreference = 'SilentlyContinue'`, - `wget ${ARTIFACT_BASE_URL}/elastic-agent-${kibanaVersion}-windows-x86_64.zip -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.zip`, + `Invoke-WebRequest -Uri https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-${kibanaVersion}-windows-x86_64.zip -OutFile elastic-agent-${kibanaVersion}-windows-x86_64.zip`, `Expand-Archive .\\elastic-agent-${kibanaVersion}-windows-x86_64.zip`, `cd elastic-agent-${kibanaVersion}-windows-x86_64`, ].join(`\n`), From 6fc0ffa3d4b2713cb770e2cd6f0cebced570923d Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Fri, 12 Aug 2022 08:57:08 -0500 Subject: [PATCH 54/59] [ML] Data Visualizer: Add functional tests for pinned filters (#138539) * [ML] Add test * [ML] Remove sample log, fix lucene Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/ml/data_visualizer/index.ts | 1 + .../index_data_visualizer_filters.ts | 142 ++++++++++++++++++ .../index_data_visualizer_grid_in_discover.ts | 1 + .../test/functional/services/ml/navigation.ts | 9 +- 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index.ts b/x-pack/test/functional/apps/ml/data_visualizer/index.ts index 6f18f80045fee8..ab14b7f3c86c0e 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index.ts @@ -33,6 +33,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./index_data_visualizer')); + loadTestFile(require.resolve('./index_data_visualizer_filters')); loadTestFile(require.resolve('./index_data_visualizer_grid_in_discover')); loadTestFile(require.resolve('./index_data_visualizer_grid_in_dashboard')); loadTestFile(require.resolve('./index_data_visualizer_actions_panel')); diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts new file mode 100644 index 00000000000000..797293e58dc891 --- /dev/null +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_filters.ts @@ -0,0 +1,142 @@ +/* + * 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 { FtrProviderContext } from '../../../ftr_provider_context'; +import { + farequoteKQLFiltersSearchTestData, + farequoteLuceneFiltersSearchTestData, + farequoteDataViewTestData, +} from './index_test_data'; +import { TestData } from './types'; + +const PINNED_FILTER = { + key: 'type.keyword', + value: 'farequote', + enabled: true, + pinned: true, + negated: false, +}; +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const ml = getService('ml'); + const PageObjects = getPageObjects(['common', 'discover', 'timePicker', 'settings', 'header']); + const filterBar = getService('filterBar'); + + const startTime = 'Jan 1, 2016 @ 00:00:00.000'; + const endTime = 'Nov 1, 2020 @ 00:00:00.000'; + + function runTests(testData: TestData) { + afterEach(async function () { + await filterBar.removeFilter(PINNED_FILTER.key); + }); + + it(`retains pinned filters from other plugins`, async () => { + await ml.navigation.navigateToDiscoverViaAppsMenu(); + await ml.dashboardEmbeddables.selectDiscoverIndexPattern('ft_farequote'); + await PageObjects.timePicker.setAbsoluteRange(startTime, endTime); + + await filterBar.addFilter(PINNED_FILTER.key, 'is', PINNED_FILTER.value); + await filterBar.toggleFilterPinned(PINNED_FILTER.key); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} navigates to ML`); + await ml.navigation.navigateToMlViaAppsMenu(); + await ml.navigation.navigateToDataVisualizer(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the saved search selection page` + ); + await ml.dataVisualizer.navigateToIndexPatternSelection(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the index data visualizer page` + ); + await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer( + testData.sourceIndexOrSavedSearch + ); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} loads data for full time range`); + await ml.dataVisualizerIndexBased.clickUseFullDataButton( + testData.expected.totalDocCountFormatted + ); + + if (Array.isArray(testData.expected?.filters)) { + await PageObjects.header.waitUntilLoadingHasFinished(); + for (const filter of testData.expected?.filters) { + await ml.dataVisualizerIndexBased.assertFilterBarFilterContent({ + key: filter.key, + value: filter.value, + enabled: true, + pinned: false, + negated: false, + }); + } + } + + await ml.dataVisualizerIndexBased.assertFilterBarFilterContent(PINNED_FILTER); + }); + + it(`retains pinned filters to other plugins`, async () => { + await ml.testExecution.logTestStep(`${testData.suiteTitle} navigates to ML`); + await ml.navigation.navigateToDataVisualizer(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the saved search selection page` + ); + await ml.dataVisualizer.navigateToIndexPatternSelection(); + + await ml.testExecution.logTestStep( + `${testData.suiteTitle} loads the index data visualizer page` + ); + await ml.jobSourceSelection.selectSourceForIndexBasedDataVisualizer( + testData.sourceIndexOrSavedSearch + ); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} loads data for full time range`); + await ml.dataVisualizerIndexBased.clickUseFullDataButton( + testData.expected.totalDocCountFormatted + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} adds a pinned filter`); + await filterBar.addFilter(PINNED_FILTER.key, 'is', PINNED_FILTER.value); + await filterBar.toggleFilterPinned(PINNED_FILTER.key); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await ml.testExecution.logTestStep(`${testData.suiteTitle} navigates to Discover`); + await ml.navigation.navigateToDiscoverViaAppsMenu(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await ml.dataVisualizerIndexBased.assertFilterBarFilterContent(PINNED_FILTER); + }); + } + describe('data visualizer with pinned global filters', function () { + before(async function () { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.createSavedSearchFarequoteFilterAndLuceneIfNeeded(); + await ml.testResources.createSavedSearchFarequoteFilterAndKueryIfNeeded(); + + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async function () { + await ml.testResources.deleteSavedSearches(); + await ml.testResources.deleteIndexPatternByTitle('ft_farequote'); + }); + + describe(`with ${farequoteDataViewTestData.suiteTitle}`, function () { + runTests(farequoteDataViewTestData); + }); + + describe(`with ${farequoteLuceneFiltersSearchTestData.suiteTitle}`, function () { + runTests(farequoteLuceneFiltersSearchTestData); + }); + describe(`with ${farequoteKQLFiltersSearchTestData.suiteTitle}`, function () { + runTests(farequoteKQLFiltersSearchTestData); + }); + }); +} diff --git a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts index 7457114c3ebaea..c0c7a47414ce59 100644 --- a/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts +++ b/x-pack/test/functional/apps/ml/data_visualizer/index_data_visualizer_grid_in_discover.ts @@ -17,6 +17,7 @@ import { farequoteLuceneSearchTestData, sampleLogTestData, } from './index_test_data'; + export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['common', 'discover', 'timePicker', 'settings']); diff --git a/x-pack/test/functional/services/ml/navigation.ts b/x-pack/test/functional/services/ml/navigation.ts index 60465a83fb42b9..bb1578cf45725c 100644 --- a/x-pack/test/functional/services/ml/navigation.ts +++ b/x-pack/test/functional/services/ml/navigation.ts @@ -17,7 +17,7 @@ export function MachineLearningNavigationProvider({ const browser = getService('browser'); const retry = getService('retry'); const testSubjects = getService('testSubjects'); - const PageObjects = getPageObjects(['common', 'header']); + const PageObjects = getPageObjects(['common', 'header', 'discover']); return { async navigateToMl() { @@ -45,6 +45,13 @@ export function MachineLearningNavigationProvider({ }); }, + async navigateToDiscoverViaAppsMenu() { + await retry.tryForTime(60 * 1000, async () => { + await appsMenu.clickLink('Discover'); + await PageObjects.discover.waitForDiscoverAppOnScreen(); + }); + }, + async navigateToStackManagementViaAppsMenu() { await retry.tryForTime(60 * 1000, async () => { await appsMenu.clickLink('Stack Management'); From c393b3d872d959d185fa01733a463e26d974245c Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Fri, 12 Aug 2022 16:28:36 +0200 Subject: [PATCH 55/59] [ML] Fix restoring a field name with the `exists` filter aggregation (#138630) * fix exists filter * update tests, fix resolving field for other filters * add type guards * fix percentiles and terms aggs --- .../public/app/common/pivot_aggs.test.ts | 81 +++++++++++++++++++ .../transform/public/app/common/pivot_aggs.ts | 9 ++- .../advanced_runtime_mappings_settings.tsx | 3 +- .../aggregation_list/popover_form.tsx | 16 ++-- .../filter_agg/components/filter_agg_form.tsx | 13 +-- .../step_define/common/filter_agg/config.ts | 53 ++++++++---- .../step_define/common/filter_agg/types.ts | 3 + .../step_define/hooks/use_pivot_config.ts | 3 +- 8 files changed, 150 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/transform/public/app/common/pivot_aggs.test.ts b/x-pack/plugins/transform/public/app/common/pivot_aggs.test.ts index f92bf1cdf59d90..84b47eca0fceb4 100644 --- a/x-pack/plugins/transform/public/app/common/pivot_aggs.test.ts +++ b/x-pack/plugins/transform/public/app/common/pivot_aggs.test.ts @@ -33,6 +33,7 @@ describe('getAggConfigFromEsAgg', () => { aggConfig: { filterAgg: 'term', aggTypeConfig: { + fieldName: 'region', FilterAggFormComponent: FilterTermForm, filterAggConfig: { value: 'sa-west-1', @@ -66,6 +67,86 @@ describe('getAggConfigFromEsAgg', () => { parentAgg: result, }); }); + + test('should resolve percentiles agg in sub-aggregations', () => { + const esConfig = { + filter: { + exists: { + field: 'customer_phone', + }, + }, + aggs: { + 'products.base_price.percentiles': { + percentiles: { + field: 'products.base_price', + percents: [1, 5, 25, 50, 75, 95, 99], + }, + }, + }, + }; + + const result = getAggConfigFromEsAgg(esConfig, 'test_sub_percentiles'); + + expect(result.subAggs!['products.base_price.percentiles']).toMatchObject({ + agg: 'percentiles', + aggName: 'products.base_price.percentiles', + dropDownName: 'products.base_price.percentiles', + field: 'products.base_price', + parentAgg: result, + }); + }); + + test('restore config for the exists filter', () => { + expect( + getAggConfigFromEsAgg({ filter: { exists: { field: 'instance' } } }, 'test_3') + ).toMatchObject({ + agg: 'filter', + aggName: 'test_3', + dropDownName: 'test_3', + field: 'instance', + aggConfig: { + filterAgg: 'exists', + aggTypeConfig: { + fieldName: 'instance', + }, + }, + }); + }); + + test('restore config for the range filter', () => { + expect( + getAggConfigFromEsAgg( + { + filter: { + range: { + 'products.base_price': { + gte: 11, + lt: 20, + }, + }, + }, + }, + 'test_4' + ) + ).toMatchObject({ + agg: 'filter', + aggName: 'test_4', + dropDownName: 'test_4', + field: 'products.base_price', + aggConfig: { + filterAgg: 'range', + aggTypeConfig: { + fieldName: 'products.base_price', + filterAggConfig: { + from: 11, + to: 20, + includeFrom: true, + includeTo: false, + }, + }, + }, + }); + }); }); describe('isSpecialSortField', () => { diff --git a/x-pack/plugins/transform/public/app/common/pivot_aggs.ts b/x-pack/plugins/transform/public/app/common/pivot_aggs.ts index 4b986659fe633d..a314a0193bcd72 100644 --- a/x-pack/plugins/transform/public/app/common/pivot_aggs.ts +++ b/x-pack/plugins/transform/public/app/common/pivot_aggs.ts @@ -171,6 +171,8 @@ export function getAggConfigFromEsAgg( } const commonConfig: PivotAggsConfigBase = { + // FIXME this spread operator set the field property + // Check if there are some extra props involved ...esAggDefinition[agg], agg, aggName, @@ -200,7 +202,7 @@ export function getAggConfigFromEsAgg( } export interface PivotAggsConfigWithUiBase extends PivotAggsConfigBase { - field: EsFieldName | EsFieldName[]; + field: EsFieldName | EsFieldName[] | null; } export interface PivotAggsConfigWithExtra extends PivotAggsConfigWithUiBase { @@ -253,7 +255,10 @@ export function isPivotAggsConfigWithUiSupport(arg: unknown): arg is PivotAggsCo type PivotAggsConfigWithExtendedForm = PivotAggsConfigFilter | PivotAggsConfigTopMetrics; export function isPivotAggsWithExtendedForm(arg: unknown): arg is PivotAggsConfigWithExtendedForm { - return isPopulatedObject(arg, ['AggFormComponent']); + return ( + (isPopulatedObject(arg) && arg.hasOwnProperty('setUiConfigFromEs')) || + isPopulatedObject(arg, ['AggFormComponent']) + ); } export function isPivotAggConfigTopMetric(arg: unknown): arg is PivotAggsConfigTopMetrics { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx index 2c0bd8d57f68ca..a07978e12ec0fa 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { isDefined } from '../../../../../../common/types/common'; import { StepDefineFormHook } from '../step_define'; import { AdvancedRuntimeMappingsEditor } from '../advanced_runtime_mappings_editor/advanced_runtime_mappings_editor'; import { AdvancedRuntimeMappingsEditorSwitch } from '../advanced_runtime_mappings_editor_switch'; @@ -80,7 +81,7 @@ export const AdvancedRuntimeMappingsSettings: FC = (props) = const newFields = agg.field.filter((f) => !isFieldDeleted(f)); updateAggregation(aggName, { ...agg, field: newFields }); } else { - if (agg.field !== undefined && isFieldDeleted(agg.field)) { + if (isDefined(agg.field) && isFieldDeleted(agg.field)) { deleteAggregation(aggName); } } diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx index 7370a4fd9287dc..040187f2395814 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.tsx @@ -107,7 +107,7 @@ export const PopoverForm: React.FC = ({ defaultData, otherAggNames, onCha const [aggName, setAggName] = useState(defaultData.aggName); const [agg, setAgg] = useState(defaultData.agg); - const [field, setField] = useState( + const [field, setField] = useState( isPivotAggsConfigWithUiSupport(defaultData) ? defaultData.field : '' ); @@ -178,6 +178,7 @@ export const PopoverForm: React.FC = ({ defaultData, otherAggNames, onCha if (agg === PIVOT_SUPPORTED_AGGS.PERCENTILES) { updatedItem = { + ...aggConfigDef, agg, aggName, field: resultField, @@ -186,6 +187,7 @@ export const PopoverForm: React.FC = ({ defaultData, otherAggNames, onCha }; } else if (agg === PIVOT_SUPPORTED_AGGS.TERMS) { updatedItem = { + ...aggConfigDef, agg, aggName, field: resultField, @@ -304,10 +306,14 @@ export const PopoverForm: React.FC = ({ defaultData, otherAggNames, onCha label: v.text as string, }; })} - selectedOptions={(typeof field === 'string' ? [field] : field).map((v) => ({ - value: v, - label: v, - }))} + selectedOptions={ + !!field + ? (typeof field === 'string' ? [field] : field).map((v) => ({ + value: v, + label: v, + })) + : [] + } onChange={(e) => { const res = e.map((v) => v.value as string); setField(res); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx index 841fdf1104346d..bb12d6358b8d9e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx @@ -63,10 +63,13 @@ export const FilterAggForm: PivotAggsConfigFilter['AggFormComponent'] = ({ [dataView, selectedField, runtimeMappings] ); - useUpdateEffect(() => { - // reset filter agg on field change - onChange({}); - }, [selectedField]); + useUpdateEffect( + function resetConfigOnFieldChange() { + // reset filter agg on field change + onChange({}); + }, + [selectedField] + ); const filterAggTypeConfig = aggConfig?.aggTypeConfig; const filterAgg = aggConfig?.filterAgg ?? ''; @@ -109,7 +112,7 @@ export const FilterAggForm: PivotAggsConfigFilter['AggFormComponent'] = ({ const filterAggUpdate = e.target.value as FilterAggType; onChange({ filterAgg: filterAggUpdate, - aggTypeConfig: getFilterAggTypeConfig(filterAggUpdate), + aggTypeConfig: getFilterAggTypeConfig(filterAggUpdate, selectedField), }); }} data-test-subj="transformFilterAggTypeSelector" diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/config.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/config.ts index 7003373bb25d70..b9d9e220720945 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/config.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/config.ts @@ -14,7 +14,6 @@ import { import { FILTERS } from './constants'; import { FilterAggForm, FilterEditorForm, FilterRangeForm, FilterTermForm } from './components'; import { - FilterAggConfigBase, FilterAggConfigBool, FilterAggConfigExists, FilterAggConfigRange, @@ -30,10 +29,13 @@ import { export function getFilterAggConfig( commonConfig: PivotAggsConfigWithUiBase | PivotAggsConfigBase ): PivotAggsConfigFilter { + const field = isPivotAggsConfigWithUiSupport(commonConfig) ? commonConfig.field : null; + return { ...commonConfig, isSubAggsSupported: true, - field: isPivotAggsConfigWithUiSupport(commonConfig) ? commonConfig.field : '', + // Field name might be missing, for instance for the bool filter. + field, AggFormComponent: FilterAggForm, aggConfig: {}, getEsAggConfig() { @@ -49,10 +51,11 @@ export function getFilterAggConfig( setUiConfigFromEs(esAggDefinition) { const filterAgg = Object.keys(esAggDefinition)[0] as FilterAggType; const filterAggConfig = esAggDefinition[filterAgg]; - const aggTypeConfig = getFilterAggTypeConfig(filterAgg, filterAggConfig); - // TODO consider moving field to the filter agg type level - this.field = Object.keys(filterAggConfig)[0]; + const aggTypeConfig = getFilterAggTypeConfig(filterAgg, field as string, filterAggConfig); + + this.field = field ?? aggTypeConfig.fieldName ?? null; + this.aggConfig = { filterAgg, aggTypeConfig, @@ -82,23 +85,28 @@ export function getFilterAggConfig( */ export function getFilterAggTypeConfig( filterAggType: FilterAggConfigUnion['filterAgg'] | FilterAggType, + fieldName?: string, esConfig?: { [key: string]: any } -): FilterAggConfigUnion['aggTypeConfig'] | FilterAggConfigBase['aggTypeConfig'] { +): FilterAggConfigUnion['aggTypeConfig'] { + let resultField = fieldName; + switch (filterAggType) { case FILTERS.TERM: const value = typeof esConfig === 'object' ? Object.values(esConfig)[0] : undefined; + resultField = esConfig ? Object.keys(esConfig)[0] : resultField; + return { FilterAggFormComponent: FilterTermForm, filterAggConfig: { value, }, - getEsAggConfig(fieldName) { - if (fieldName === undefined || !this.filterAggConfig) { + getEsAggConfig() { + if (this.fieldName === undefined || !this.filterAggConfig) { throw new Error(`Config ${FILTERS.TERM} is not completed`); } return { - [fieldName]: this.filterAggConfig.value, + [this.fieldName]: this.filterAggConfig.value, }; }, isValid() { @@ -107,11 +115,15 @@ export function getFilterAggTypeConfig( getAggName() { return this.filterAggConfig?.value ? this.filterAggConfig.value : undefined; }, + fieldName: resultField, } as FilterAggConfigTerm['aggTypeConfig']; case FILTERS.RANGE: + resultField = esConfig ? Object.keys(esConfig)[0] : resultField; + const esFilterRange = typeof esConfig === 'object' ? Object.values(esConfig)[0] : undefined; return { + fieldName: resultField, FilterAggFormComponent: FilterRangeForm, filterAggConfig: typeof esFilterRange === 'object' @@ -119,11 +131,11 @@ export function getFilterAggTypeConfig( from: esFilterRange.gte ?? esFilterRange.gt, to: esFilterRange.lte ?? esFilterRange.lt, includeFrom: esFilterRange.gte !== undefined, - includeTo: esFilterRange.lts !== undefined, + includeTo: esFilterRange.lte !== undefined, } : undefined, - getEsAggConfig(fieldName) { - if (fieldName === undefined || !this.filterAggConfig) { + getEsAggConfig() { + if (this.fieldName === undefined || !this.filterAggConfig) { throw new Error(`Config ${FILTERS.RANGE} is not completed`); } @@ -140,7 +152,7 @@ export function getFilterAggTypeConfig( } return { - [fieldName]: result, + [this.fieldName]: result, }; }, isValid() { @@ -167,15 +179,21 @@ export function getFilterAggTypeConfig( }, } as FilterAggConfigRange['aggTypeConfig']; case FILTERS.EXISTS: + resultField = esConfig ? esConfig.field : resultField; + return { - getEsAggConfig(fieldName) { - if (fieldName === undefined) { + fieldName: resultField, + getEsAggConfig() { + if (this.fieldName === undefined) { throw new Error(`Config ${FILTERS.EXISTS} is not completed`); } return { - field: fieldName, + field: this.fieldName, }; }, + isValid() { + return typeof this.fieldName === 'string'; + }, } as FilterAggConfigExists['aggTypeConfig']; case FILTERS.BOOL: return { @@ -192,12 +210,13 @@ export function getFilterAggTypeConfig( isValid() { return jsonStringValidator(this.filterAggConfig); }, - getEsAggConfig(fieldName) { + getEsAggConfig() { return JSON.parse(this.filterAggConfig!); }, } as FilterAggConfigBool['aggTypeConfig']; default: return { + fieldName, FilterAggFormComponent: FilterEditorForm, filterAggConfig: '', getEsAggConfig() { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/types.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/types.ts index f7fcf18f76b36e..d716710bcbb29a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/types.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/types.ts @@ -29,11 +29,14 @@ interface FilterAggTypeConfig { filterAggConfig?: U extends undefined ? undefined : U; /** Converts UI agg config form to ES agg request object */ getEsAggConfig: (field?: string) => R; + /** Validation result of the filter agg config */ isValid?: () => boolean; /** Provides aggregation name generated based on the configuration */ getAggName?: () => string | undefined; /** Helper text for the aggregation reflecting some configuration info */ helperText?: () => string | undefined; + /** Field name. In some cases, e.g. `exists` filter, it's resolved from the filter agg definition */ + fieldName?: string; } /** Filter agg type definition */ diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/hooks/use_pivot_config.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/hooks/use_pivot_config.ts index 75450a4df16c1b..7be29aa6888240 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/hooks/use_pivot_config.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/hooks/use_pivot_config.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { KBN_FIELD_TYPES } from '@kbn/data-plugin/common'; import { AggName } from '../../../../../../../common/types/aggregations'; -import { dictionaryToArray } from '../../../../../../../common/types/common'; +import { dictionaryToArray, isDefined } from '../../../../../../../common/types/common'; import { useToastNotifications } from '../../../../../app_dependencies'; import { @@ -190,6 +190,7 @@ export const usePivotConfig = ( Object.values(aggList) .map((v) => (isPivotAggConfigWithUiSupport(v) ? v.field : undefined)) .flat() + .filter(isDefined) ), ].find((v) => fields.find((x) => x.name === v)?.type === KBN_FIELD_TYPES.DATE); } From 6221b4fd7088fb6f0a251dd2c4d1e927384ba1fe Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Fri, 12 Aug 2022 09:49:35 -0500 Subject: [PATCH 56/59] batch 1 of removing es_archives/empty_kibana (#138189) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../advanced_settings_spaces.ts | 5 +++-- .../feature_controls/ccr_security.ts | 6 +++--- .../controls_migration_smoke_test.ts | 2 +- .../lens_migration_smoke_test.ts | 2 +- .../tsvb_migration_smoke_test.ts | 4 ++-- .../visualize_migration_smoke_test.ts | 2 +- .../data_views/feature_controls/security.ts | 4 ++-- .../apps/data_views/feature_controls/spaces.ts | 9 +++++---- .../functional/apps/data_views/spaces/index.ts | 3 ++- .../feature_controls/dev_tools_security.ts | 4 ++-- .../feature_controls/dev_tools_spaces.ts | 6 +++--- .../graph/feature_controls/graph_security.ts | 4 ++-- .../graph/feature_controls/graph_spaces.ts | 4 ++-- x-pack/test/functional/apps/graph/graph.ts | 2 +- .../feature_controls/ilm_security.ts | 6 +++--- .../index_management_security.ts | 6 +++--- .../feature_controls/infrastructure_spaces.ts | 18 +++++++++--------- .../infra/feature_controls/logs_security.ts | 4 ++-- .../apps/infra/feature_controls/logs_spaces.ts | 10 +++++----- x-pack/test/functional/apps/infra/home_page.ts | 3 ++- .../apps/infra/logs_source_configuration.ts | 5 +++-- .../functional/apps/infra/metrics_anomalies.ts | 4 ++-- .../functional/apps/infra/metrics_explorer.ts | 3 ++- .../apps/infra/metrics_source_configuration.ts | 5 +++-- .../ingest_pipelines_security.ts | 6 +++--- .../license_management_security.ts | 6 +++--- .../feature_controls/logstash_security.ts | 6 +++--- .../feature_controls/management_security.ts | 6 +++--- .../feature_controls/monitoring_security.ts | 6 +++--- .../feature_controls/monitoring_spaces.ts | 6 +++--- .../remote_clusters_security.ts | 6 +++--- .../reporting_management/report_listing.ts | 6 +++--- .../functional/apps/rollup_job/rollup_jobs.js | 4 ++-- .../import_saved_objects_between_versions.ts | 4 ++-- .../apps/security/doc_level_security_roles.ts | 3 ++- .../test/functional/apps/security/security.ts | 6 +++--- .../spaces/feature_controls/spaces_security.ts | 6 +++--- .../functional/apps/status_page/status_page.ts | 6 +++--- .../feature_controls/transform_security.ts | 6 +++--- .../uptime/feature_controls/uptime_security.ts | 4 ++-- .../functional/page_objects/security_page.ts | 3 ++- 41 files changed, 110 insertions(+), 101 deletions(-) diff --git a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts index 0d1c525f569044..2b5c01a7769c8b 100644 --- a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts +++ b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts @@ -15,6 +15,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); const config = getService('config'); + const kibanaServer = getService('kibanaServer'); describe('spaces feature controls', () => { before(async () => { @@ -62,7 +63,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -72,7 +73,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`redirects to management home`, async () => { diff --git a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/ccr_security.ts b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/ccr_security.ts index a7947f0ffdf6b2..c8ecc01e608577 100644 --- a/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/ccr_security.ts +++ b/x-pack/test/functional/apps/cross_cluster_replication/feature_controls/ccr_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,12 +17,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/controls_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/controls_migration_smoke_test.ts index 658581d1297f72..d36d2b579ae628 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/controls_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/controls_migration_smoke_test.ts @@ -46,7 +46,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/getting_started/shakespeare'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should be able to import dashboard with controls from 8.0.0', async () => { diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts index 32c6449ad97b5b..024c045c4ff87f 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts @@ -36,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/getting_started/shakespeare'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should be able to import dashboard with various Lens panels from 7.12.1', async () => { diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts index 0c3f9c652a6ec8..8485f85dd35a0a 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts @@ -79,7 +79,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); }); @@ -125,7 +125,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); }); }); diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts index f4e86217a4d758..4824fcb4218287 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts @@ -36,7 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/getting_started/shakespeare'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should be able to import dashboard with various Visualize panels from 7.12.1', async () => { diff --git a/x-pack/test/functional/apps/data_views/feature_controls/security.ts b/x-pack/test/functional/apps/data_views/feature_controls/security.ts index 10c13fc588efcd..aa76093e14939a 100644 --- a/x-pack/test/functional/apps/data_views/feature_controls/security.ts +++ b/x-pack/test/functional/apps/data_views/feature_controls/security.ts @@ -19,12 +19,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global data views all privileges', () => { diff --git a/x-pack/test/functional/apps/data_views/feature_controls/spaces.ts b/x-pack/test/functional/apps/data_views/feature_controls/spaces.ts index 2bac1e844f3c0e..847b639370723c 100644 --- a/x-pack/test/functional/apps/data_views/feature_controls/spaces.ts +++ b/x-pack/test/functional/apps/data_views/feature_controls/spaces.ts @@ -15,6 +15,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'security']); const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); + const kibanaServer = getService('kibanaServer'); describe('spaces', () => { before(async () => { @@ -25,7 +26,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', @@ -36,7 +37,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('shows Management navlink', async () => { @@ -58,7 +59,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -68,7 +69,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`redirects to management home`, async () => { diff --git a/x-pack/test/functional/apps/data_views/spaces/index.ts b/x-pack/test/functional/apps/data_views/spaces/index.ts index ac891070e8e0f4..fa2b954c47cc62 100644 --- a/x-pack/test/functional/apps/data_views/spaces/index.ts +++ b/x-pack/test/functional/apps/data_views/spaces/index.ts @@ -19,12 +19,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const spacesService = getService('spaces'); const esArchiver = getService('esArchiver'); const testSubjects = getService('testSubjects'); + const kibanaServer = getService('kibanaServer'); describe('spaces', function () { this.tags('skipFirefox'); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); }); diff --git a/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_security.ts b/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_security.ts index f7ded778660fa5..5f0d5f67595215 100644 --- a/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_security.ts +++ b/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'console', 'security', 'error']); const appsMenu = getService('appsMenu'); @@ -19,7 +19,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); // ensure we're logged out so we can login as the appropriate users await PageObjects.security.forceLogout(); diff --git a/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_spaces.ts b/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_spaces.ts index 2aa9a4de922f01..3cd9c3e15c77e7 100644 --- a/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_spaces.ts +++ b/x-pack/test/functional/apps/dev_tools/feature_controls/dev_tools_spaces.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'dashboard', 'security', 'spaceSelector', 'error']); const appsMenu = getService('appsMenu'); @@ -18,11 +18,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('spaces', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('space with no features disabled', () => { diff --git a/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts b/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts index a1f0e3db2c1878..e806e2be4daf11 100644 --- a/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts +++ b/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'graph', 'security', 'error']); const testSubjects = getService('testSubjects'); @@ -18,7 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); // ensure we're logged out so we can login as the appropriate users await PageObjects.security.forceLogout(); }); diff --git a/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts b/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts index a1911bf5f02be0..c3b0804d2964af 100644 --- a/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts +++ b/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'graph', 'security', 'error']); const testSubjects = getService('testSubjects'); @@ -17,7 +17,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('spaces', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('space with no features disabled', () => { before(async () => { diff --git a/x-pack/test/functional/apps/graph/graph.ts b/x-pack/test/functional/apps/graph/graph.ts index 569441d26271b1..f126384071b3df 100644 --- a/x-pack/test/functional/apps/graph/graph.ts +++ b/x-pack/test/functional/apps/graph/graph.ts @@ -20,7 +20,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.setWindowSize(1600, 1000); log.debug('load graph/secrepo data'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/graph/secrepo'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('settings'); log.debug('create secrepo index pattern'); await PageObjects.settings.createIndexPattern('secrepo', '@timestamp'); diff --git a/x-pack/test/functional/apps/index_lifecycle_management/feature_controls/ilm_security.ts b/x-pack/test/functional/apps/index_lifecycle_management/feature_controls/ilm_security.ts index 0150d965e8593a..78c6e6d6e99701 100644 --- a/x-pack/test/functional/apps/index_lifecycle_management/feature_controls/ilm_security.ts +++ b/x-pack/test/functional/apps/index_lifecycle_management/feature_controls/ilm_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,12 +17,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/index_management/feature_controls/index_management_security.ts b/x-pack/test/functional/apps/index_management/feature_controls/index_management_security.ts index 4d21435842b48a..7d94e7e3d85c87 100644 --- a/x-pack/test/functional/apps/index_management/feature_controls/index_management_security.ts +++ b/x-pack/test/functional/apps/index_management/feature_controls/index_management_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,12 +17,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_spaces.ts b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_spaces.ts index 263bf1c9b0d379..43369dd7c6d448 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_spaces.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_spaces.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'infraHome', 'security', 'spaceSelector']); const testSubjects = getService('testSubjects'); @@ -17,11 +17,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('infrastructure spaces', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('space with no features disabled', () => { @@ -59,7 +59,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -69,7 +69,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`doesn't show infrastructure navlink`, async () => { @@ -101,7 +101,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -111,7 +111,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`Infrastructure app is accessible`, async () => { @@ -126,7 +126,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -136,7 +136,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`Infrastructure app is accessible`, async () => { diff --git a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts index 8908a342983733..73e5a5b400884e 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/logs_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'error', 'infraHome', 'security']); const testSubjects = getService('testSubjects'); @@ -18,7 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('logs security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global logs all privileges', () => { before(async () => { diff --git a/x-pack/test/functional/apps/infra/feature_controls/logs_spaces.ts b/x-pack/test/functional/apps/infra/feature_controls/logs_spaces.ts index 9c5e5667cf39cc..570515a2d9614c 100644 --- a/x-pack/test/functional/apps/infra/feature_controls/logs_spaces.ts +++ b/x-pack/test/functional/apps/infra/feature_controls/logs_spaces.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'infraHome', 'security', 'spaceSelector']); const testSubjects = getService('testSubjects'); @@ -20,7 +20,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', @@ -31,7 +31,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('shows Logs navlink', async () => { @@ -59,7 +59,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -69,7 +69,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`doesn't show Logs navlink`, async () => { diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 9c52b38af95b2d..6acaabcd5d2072 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -16,11 +16,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const retry = getService('retry'); const pageObjects = getPageObjects(['common', 'infraHome', 'infraSavedViews']); + const kibanaServer = getService('kibanaServer'); describe('Home page', function () { this.tags('includeFirefox'); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('without metrics present', () => { diff --git a/x-pack/test/functional/apps/infra/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs_source_configuration.ts index 41ff5c70033217..56eed5ec4b6352 100644 --- a/x-pack/test/functional/apps/infra/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs_source_configuration.ts @@ -21,13 +21,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'header', 'infraLogs']); const retry = getService('retry'); const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); describe('Logs Source Configuration', function () { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('Allows indices configuration', () => { diff --git a/x-pack/test/functional/apps/infra/metrics_anomalies.ts b/x-pack/test/functional/apps/infra/metrics_anomalies.ts index a1619467fe6bb4..bdda5aa0a3e9fd 100644 --- a/x-pack/test/functional/apps/infra/metrics_anomalies.ts +++ b/x-pack/test/functional/apps/infra/metrics_anomalies.ts @@ -17,10 +17,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Metrics UI Anomaly Flyout', function () { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('with no anomalies present', () => { diff --git a/x-pack/test/functional/apps/infra/metrics_explorer.ts b/x-pack/test/functional/apps/infra/metrics_explorer.ts index 6b1873b7b5e394..fc620d9ba56650 100644 --- a/x-pack/test/functional/apps/infra/metrics_explorer.ts +++ b/x-pack/test/functional/apps/infra/metrics_explorer.ts @@ -15,6 +15,7 @@ const timepickerFormat = 'MMM D, YYYY @ HH:mm:ss.SSS'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const pageObjects = getPageObjects([ 'common', 'infraHome', @@ -26,7 +27,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Metrics Explorer', function () { this.tags('includeFirefox'); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('Basic Functionality', () => { diff --git a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts index 5d2f7b09ab1673..564b07b1ce1a49 100644 --- a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts @@ -14,13 +14,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const infraSourceConfigurationForm = getService('infraSourceConfigurationForm'); const pageObjects = getPageObjects(['common', 'infraHome']); + const kibanaServer = getService('kibanaServer'); describe('Infrastructure Source Configuration', function () { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('with metrics present', () => { diff --git a/x-pack/test/functional/apps/ingest_pipelines/feature_controls/ingest_pipelines_security.ts b/x-pack/test/functional/apps/ingest_pipelines/feature_controls/ingest_pipelines_security.ts index e956084a96d2e1..3e7a1f2f2146a4 100644 --- a/x-pack/test/functional/apps/ingest_pipelines/feature_controls/ingest_pipelines_security.ts +++ b/x-pack/test/functional/apps/ingest_pipelines/feature_controls/ingest_pipelines_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -18,12 +18,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // FLAKY: https://github.com/elastic/kibana/issues/132159 describe.skip('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/license_management/feature_controls/license_management_security.ts b/x-pack/test/functional/apps/license_management/feature_controls/license_management_security.ts index 9faade3907e724..35e39af779ba45 100644 --- a/x-pack/test/functional/apps/license_management/feature_controls/license_management_security.ts +++ b/x-pack/test/functional/apps/license_management/feature_controls/license_management_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,12 +17,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/logstash/feature_controls/logstash_security.ts b/x-pack/test/functional/apps/logstash/feature_controls/logstash_security.ts index bb12768c85ca6e..c8b7284616427d 100644 --- a/x-pack/test/functional/apps/logstash/feature_controls/logstash_security.ts +++ b/x-pack/test/functional/apps/logstash/feature_controls/logstash_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,12 +17,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/management/feature_controls/management_security.ts b/x-pack/test/functional/apps/management/feature_controls/management_security.ts index 5af7aeda6440cc..c1e09d9f3eaab8 100644 --- a/x-pack/test/functional/apps/management/feature_controls/management_security.ts +++ b/x-pack/test/functional/apps/management/feature_controls/management_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -18,12 +18,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('no management privileges', () => { diff --git a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts index 80483503982b12..a509babff77e5e 100644 --- a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts +++ b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const appsMenu = getService('appsMenu'); const PageObjects = getPageObjects(['common', 'security']); @@ -17,7 +17,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await security.role.create('global_all_role', { elasticsearch: { @@ -40,7 +40,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // NOTE: Logout needs to happen before anything else to avoid flaky behavior await PageObjects.security.forceLogout(); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await security.role.delete('global_all_role'); }); diff --git a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts index 4450d8c280a88e..35708d1d948b97 100644 --- a/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts +++ b/x-pack/test/functional/apps/monitoring/feature_controls/monitoring_spaces.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'dashboard', 'security', 'error']); const appsMenu = getService('appsMenu'); @@ -17,13 +17,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('spaces', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { // NOTE: Logout needs to happen before anything else to avoid flaky behavior await PageObjects.security.forceLogout(); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('space with no features disabled', () => { diff --git a/x-pack/test/functional/apps/remote_clusters/feature_controls/remote_clusters_security.ts b/x-pack/test/functional/apps/remote_clusters/feature_controls/remote_clusters_security.ts index a5c8616beca297..03e0c69a276f48 100644 --- a/x-pack/test/functional/apps/remote_clusters/feature_controls/remote_clusters_security.ts +++ b/x-pack/test/functional/apps/remote_clusters/feature_controls/remote_clusters_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -18,12 +18,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // Failing: See https://github.com/elastic/kibana/issues/138129 describe.skip('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/reporting_management/report_listing.ts b/x-pack/test/functional/apps/reporting_management/report_listing.ts index 08d585b9aa5710..bbc2c979d6d3d6 100644 --- a/x-pack/test/functional/apps/reporting_management/report_listing.ts +++ b/x-pack/test/functional/apps/reporting_management/report_listing.ts @@ -14,7 +14,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const log = getService('log'); const retry = getService('retry'); const security = getService('security'); - + const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); const esArchiver = getService('esArchiver'); @@ -24,7 +24,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 'kibana_admin', // to access stack management 'reporting_user', // NOTE: the built-in role granting full reporting access is deprecated. See xpack.reporting.roles.enabled ]); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); beforeEach(async () => { @@ -35,7 +35,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await security.testUser.restoreDefaults(); }); diff --git a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js index e88082e9f00a89..abf01f63c46766 100644 --- a/x-pack/test/functional/apps/rollup_job/rollup_jobs.js +++ b/x-pack/test/functional/apps/rollup_job/rollup_jobs.js @@ -11,10 +11,10 @@ import { mockIndices } from './hybrid_index_helper'; export default function ({ getService, getPageObjects }) { const es = getService('es'); - const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['rollup', 'common', 'security']); const security = getService('security'); const esDeleteAllIndices = getService('esDeleteAllIndices'); + const kibanaServer = getService('kibanaServer'); describe('rollup job', function () { //Since rollups can only be created once with the same name (even if you delete it), @@ -71,7 +71,7 @@ export default function ({ getService, getPageObjects }) { //Delete all data indices that were created. await esDeleteAllIndices([targetIndexName, rollupSourceIndexPattern]); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await security.testUser.restoreDefaults(); }); }); diff --git a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts index 8716b10150d798..f4b6ad3fe20c86 100644 --- a/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts +++ b/x-pack/test/functional/apps/saved_objects_management/import_saved_objects_between_versions.ts @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Export import saved objects between versions', function () { before(async function () { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await esArchiver.loadIfNeeded( 'test/functional/fixtures/es_archiver/getting_started/shakespeare' @@ -44,7 +44,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await esArchiver.unload('test/functional/fixtures/es_archiver/getting_started/shakespeare'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should be able to import 7.13 saved objects into 8.0.0 and verfiy the rendering of two dashboards', async function () { diff --git a/x-pack/test/functional/apps/security/doc_level_security_roles.ts b/x-pack/test/functional/apps/security/doc_level_security_roles.ts index 65811fbf5e1185..56feb76394b618 100644 --- a/x-pack/test/functional/apps/security/doc_level_security_roles.ts +++ b/x-pack/test/functional/apps/security/doc_level_security_roles.ts @@ -17,10 +17,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const screenshot = getService('screenshots'); const security = getService('security'); const PageObjects = getPageObjects(['security', 'common', 'header', 'discover', 'settings']); + const kibanaServer = getService('kibanaServer'); describe('dls', function () { before('initialize tests', async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/security/dlstest'); await browser.setWindowSize(1600, 1000); diff --git a/x-pack/test/functional/apps/security/security.ts b/x-pack/test/functional/apps/security/security.ts index 75748be05695d1..694e227b8e2c50 100644 --- a/x-pack/test/functional/apps/security/security.ts +++ b/x-pack/test/functional/apps/security/security.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['security', 'spaceSelector']); const testSubjects = getService('testSubjects'); const spaces = getService('spaces'); @@ -21,12 +21,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { this.tags('includeFirefox'); describe('Login Page', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.security.forceLogout(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); afterEach(async () => { diff --git a/x-pack/test/functional/apps/spaces/feature_controls/spaces_security.ts b/x-pack/test/functional/apps/spaces/feature_controls/spaces_security.ts index 101a24754898e2..be03af7c896a0b 100644 --- a/x-pack/test/functional/apps/spaces/feature_controls/spaces_security.ts +++ b/x-pack/test/functional/apps/spaces/feature_controls/spaces_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security', 'spaceSelector']); const appsMenu = getService('appsMenu'); @@ -18,7 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security feature controls', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await spaces.create({ id: 'nondefaultspace', name: 'Non-default Space', @@ -28,7 +28,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spaces.delete('nondefaultspace'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all base privilege', () => { diff --git a/x-pack/test/functional/apps/status_page/status_page.ts b/x-pack/test/functional/apps/status_page/status_page.ts index f69ef940950984..a64e7dfac3de15 100644 --- a/x-pack/test/functional/apps/status_page/status_page.ts +++ b/x-pack/test/functional/apps/status_page/status_page.ts @@ -11,13 +11,13 @@ export default function statusPageFunctonalTests({ getService, getPageObjects, }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['security', 'statusPage', 'common']); describe('Status Page', function () { this.tags(['skipCloud', 'includeFirefox']); - before(async () => await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - after(async () => await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + before(async () => await kibanaServer.savedObjects.cleanStandardList()); + after(async () => await kibanaServer.savedObjects.cleanStandardList()); it('allows user to navigate without authentication', async () => { await PageObjects.security.forceLogout(); diff --git a/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts b/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts index e49a27a5f9e00b..5901ee60c72120 100644 --- a/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts +++ b/x-pack/test/functional/apps/transform/feature_controls/transform_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'settings', 'security']); const appsMenu = getService('appsMenu'); @@ -17,13 +17,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.security.forceLogout(); await PageObjects.common.navigateToApp('home'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global all privileges (aka kibana_admin)', () => { diff --git a/x-pack/test/functional/apps/uptime/feature_controls/uptime_security.ts b/x-pack/test/functional/apps/uptime/feature_controls/uptime_security.ts index b90337c3648b26..922b65fe36ce54 100644 --- a/x-pack/test/functional/apps/uptime/feature_controls/uptime_security.ts +++ b/x-pack/test/functional/apps/uptime/feature_controls/uptime_security.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const PageObjects = getPageObjects(['common', 'error', 'timePicker', 'security']); const testSubjects = getService('testSubjects'); @@ -18,7 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); // ensure we're logged out so we can login as the appropriate users await PageObjects.security.forceLogout(); }); diff --git a/x-pack/test/functional/page_objects/security_page.ts b/x-pack/test/functional/page_objects/security_page.ts index 3f4dc6056d8d22..910fc9fc5e5639 100644 --- a/x-pack/test/functional/page_objects/security_page.ts +++ b/x-pack/test/functional/page_objects/security_page.ts @@ -30,6 +30,7 @@ export class SecurityPageObject extends FtrService { private readonly log = this.ctx.getService('log'); private readonly testSubjects = this.ctx.getService('testSubjects'); private readonly esArchiver = this.ctx.getService('esArchiver'); + private readonly kibanaServer = this.ctx.getService('kibanaServer'); private readonly userMenu = this.ctx.getService('userMenu'); private readonly comboBox = this.ctx.getService('comboBox'); private readonly supertest = this.ctx.getService('supertestWithoutAuth'); @@ -233,7 +234,7 @@ export class SecurityPageObject extends FtrService { async initTests() { this.log.debug('SecurityPage:initTests'); - await this.esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await this.kibanaServer.savedObjects.cleanStandardList(); await this.esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await this.browser.setWindowSize(1600, 1000); } From 0b8d2edc17ec1a812baa12e211723c08a79668f4 Mon Sep 17 00:00:00 2001 From: doakalexi <109488926+doakalexi@users.noreply.github.com> Date: Fri, 12 Aug 2022 11:16:02 -0400 Subject: [PATCH 57/59] [ResponseOps][Alerting] clarify doc on mute/unmute alert instance id's (#138657) * Updating docs * Adding missing word * Update docs/api/alerting/mute_alert.asciidoc Co-authored-by: Lisa Cawley * Update docs/api/alerting/unmute_alert.asciidoc Co-authored-by: Lisa Cawley Co-authored-by: Lisa Cawley --- docs/api/alerting/mute_alert.asciidoc | 2 +- docs/api/alerting/unmute_alert.asciidoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/alerting/mute_alert.asciidoc b/docs/api/alerting/mute_alert.asciidoc index 4ebf12d1ce10c6..eef2f055b816da 100644 --- a/docs/api/alerting/mute_alert.asciidoc +++ b/docs/api/alerting/mute_alert.asciidoc @@ -20,7 +20,7 @@ Mute an alert. (Required, string) The ID of the rule whose alert you want to mute. `alert_id`:: - (Required, string) The ID of the alert that you want to mute. + (Required, string) The ID of the alert that you want to mute. The `alert_id` is generated by the rule and might be any arbitrary string. `space_id`:: (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. diff --git a/docs/api/alerting/unmute_alert.asciidoc b/docs/api/alerting/unmute_alert.asciidoc index 6e8870bb2fdaeb..4cae7593f99f12 100644 --- a/docs/api/alerting/unmute_alert.asciidoc +++ b/docs/api/alerting/unmute_alert.asciidoc @@ -20,7 +20,7 @@ Unmute an alert. (Required, string) The ID of the rule whose alert you want to mute. `alert_id`:: - (Required, string) The ID of the alert that you want to unmute. + (Required, string) The ID of the alert that you want to unmute. The `alert_id` is generated by the rule and might be any arbitrary string. `space_id`:: (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. From 800cc727e4d0b1a4a345f3d2b73adb4c36363641 Mon Sep 17 00:00:00 2001 From: Vitalii Dmyterko <92328789+vitaliidm@users.noreply.github.com> Date: Fri, 12 Aug 2022 17:02:18 +0100 Subject: [PATCH 58/59] [Security Solution][Detections] fixes tests related to prebuilt rules update (#138625) ## Summary fixes tests related to prebuilt rules update tests failures(https://github.com/elastic/kibana/pull/138574#issuecomment-1211348195): - removed hardcoded rule version value - required_fields are not tested agains empty array, but agains actual immutable rule value --- .../group1/update_actions.ts | 30 ++++++++++++++----- .../usage_collector/detection_rules.ts | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts index 53062e2c2cae66..e9e7e18ea31892 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/update_actions.ts @@ -104,7 +104,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForRuleSuccessOrStatus(supertest, log, updatedRule.id); }); - it('should be able to create a new webhook action and attach it to an immutable rule', async () => { + it('should not change properties of immutable rule when applying actions to it', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json @@ -120,10 +120,27 @@ export default ({ getService }: FtrProviderContext) => { rule_id: immutableRule.rule_id, // Rule id should match the same as the immutable rule version: immutableRule.version, // This version number should not change when an immutable rule is updated immutable: true, // It should stay immutable true when returning + required_fields: immutableRule.required_fields, // required_fields cannot be modified, so newRuleToUpdate will have required_fields from immutable rule }; expect(bodyToCompare).to.eql(expected); }); + it('should be able to create a new webhook action and attach it to an immutable rule', async () => { + await installPrePackagedRules(supertest, log); + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint.json + const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + const hookAction = await createNewAction(supertest, log); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); + const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, false, newRuleToUpdate); + const updatedRule = await updateRule(supertest, log, ruleToUpdate); + const bodyToCompare = removeServerGeneratedProperties(updatedRule); + + const expected = getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`); + + expect(bodyToCompare.actions).to.eql(expected.actions); + }); + it('should be able to create a new webhook action, attach it to an immutable rule and the count of prepackaged rules should not increase. If this fails, suspect the immutable tags are not staying on the rule correctly.', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: @@ -155,13 +172,10 @@ export default ({ getService }: FtrProviderContext) => { expect(body.data.length).to.eql(1); // should have only one length to the data set, otherwise we have duplicates or the tags were removed and that is incredibly bad. const bodyToCompare = removeServerGeneratedProperties(body.data[0]); - const expected = { - ...getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`), - rule_id: immutableRule.rule_id, // Rule id should match the same as the immutable rule - version: immutableRule.version, // This version number should not change when an immutable rule is updated - immutable: true, // It should stay immutable true when returning - }; - expect(bodyToCompare).to.eql(expected); + const expected = getSimpleRuleOutputWithWebHookAction(`${bodyToCompare.actions?.[0].id}`); + + expect(bodyToCompare.actions).to.eql(expected.actions); + expect(bodyToCompare.immutable).to.be(true); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts index febaf8df1890f6..dbc8f5169c6706 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group4/telemetry/usage_collector/detection_rules.ts @@ -1315,12 +1315,12 @@ export default ({ getService }: FtrProviderContext) => { created_on: createdOn, updated_on: updatedOn, rule_id: ruleId, + rule_version: ruleVersion, ...omittedFields } = foundRule; expect(omittedFields).to.eql({ rule_name: 'Endpoint Security', rule_type: 'query', - rule_version: 3, enabled: true, elastic_rule: true, alert_count_daily: 0, From a9a1828a23b41bcf07f58f170d01de12fc849994 Mon Sep 17 00:00:00 2001 From: liza-mae Date: Fri, 12 Aug 2022 10:03:18 -0600 Subject: [PATCH 59/59] Fix console tests on cloud (#138682) * Fix console test on cloud * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * Fix access to sample data * Clean up access after test * Fix restore test Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/apps/console/_console.ts | 19 +++++++++++++++++-- test/functional/apps/console/_vector_tile.ts | 3 +++ test/functional/config.base.js | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/test/functional/apps/console/_console.ts b/test/functional/apps/console/_console.ts index 0878442156ab7c..57aab9b80bb668 100644 --- a/test/functional/apps/console/_console.ts +++ b/test/functional/apps/console/_console.ts @@ -28,6 +28,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const PageObjects = getPageObjects(['common', 'console', 'header']); const toasts = getService('toasts'); + const security = getService('security'); + const testSubjects = getService('testSubjects'); describe('console app', function describeIndexTests() { this.tags('includeFirefox'); @@ -151,7 +153,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.console.clickPlay(); }; + before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_index']); + }); + + after(async () => { + await security.testUser.restoreDefaults(); + }); + beforeEach(async () => { + // Welcome fly out exists sometimes + const flyOutExists = await testSubjects.exists('euiFlyoutCloseButton'); + if (flyOutExists) { + await testSubjects.click('euiFlyoutCloseButton'); + } await PageObjects.console.clearTextArea(); }); @@ -160,8 +175,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { const response = await PageObjects.console.getResponse(); log.debug(response); - expect(response).to.contain('# PUT test-index 200 OK'); - expect(response).to.contain('# DELETE test-index 200 OK'); + expect(response).to.contain('# PUT test-index 200'); + expect(response).to.contain('# DELETE test-index 200'); }); }); diff --git a/test/functional/apps/console/_vector_tile.ts b/test/functional/apps/console/_vector_tile.ts index 3959877fdf685b..77b186227ed288 100644 --- a/test/functional/apps/console/_vector_tile.ts +++ b/test/functional/apps/console/_vector_tile.ts @@ -12,9 +12,11 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'console', 'header', 'home']); const retry = getService('retry'); + const security = getService('security'); describe('console vector tiles response validation', function describeIndexTests() { before(async () => { + await security.testUser.setRoles(['kibana_admin', 'kibana_sample_admin']); await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { useActualUrl: true, }); @@ -41,6 +43,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.home.removeSampleDataSet('logs'); + await security.testUser.restoreDefaults(); }); }); } diff --git a/test/functional/config.base.js b/test/functional/config.base.js index dd576cbbd4f495..d543f13755ccea 100644 --- a/test/functional/config.base.js +++ b/test/functional/config.base.js @@ -249,6 +249,21 @@ export default async function ({ readConfigFile }) { kibana: [], }, + test_index: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['test-index'], + privileges: ['read', 'view_index_metadata', 'manage', 'create_index', 'index'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + index_a: { elasticsearch: { cluster: [],

    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≤b1u4ji_pVNLur>(y%dfCRgbm(AjF07s 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