From aa38fb68a7473aec1c341e759a0d9e622d4c346a Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 6 Jan 2020 11:43:15 +0100 Subject: [PATCH 1/3] Migrate config deprecations and `ShieldUser` functionality to the New Platform (#53768) --- .../framework/kibana_framework_adapter.ts | 8 ++- .../components/pipeline_edit/pipeline_edit.js | 4 +- x-pack/legacy/plugins/security/index.js | 18 +---- .../legacy/plugins/security/public/lib/api.ts | 6 +- .../security/public/services/shield_user.js | 33 --------- .../security/public/views/account/account.js | 26 +++---- .../account_management_page.test.tsx | 71 ++++++++++++++++--- .../components/account_management_page.tsx | 44 +++++++----- .../views/management/edit_role/index.js | 7 +- .../components/edit_user_page.test.tsx | 71 ++++++++++++------- .../edit_user/components/edit_user_page.tsx | 6 +- .../views/management/edit_user/edit_user.js | 9 ++- .../public/views/management/management.js | 15 ++-- .../views/management/users_grid/users.js | 1 - .../overwritten_session.tsx | 52 +++++++------- .../authentication/authentication_service.ts | 31 ++++++++ .../public/authentication/index.mock.ts | 13 ++++ .../security/public/authentication/index.ts | 7 ++ x-pack/plugins/security/public/index.ts | 3 + x-pack/plugins/security/public/mocks.ts | 19 +++++ .../nav_control/nav_control_service.test.ts | 12 +++- .../nav_control/nav_control_service.tsx | 21 +++--- x-pack/plugins/security/public/plugin.ts | 9 ++- .../plugins/security/public/session/index.ts | 2 +- .../public/session/session_timeout.tsx | 2 +- x-pack/plugins/security/server/config.ts | 15 +--- x-pack/plugins/security/server/index.ts | 27 +++++-- x-pack/plugins/security/server/plugin.ts | 7 +- 28 files changed, 326 insertions(+), 213 deletions(-) delete mode 100644 x-pack/legacy/plugins/security/public/services/shield_user.js create mode 100644 x-pack/plugins/security/public/authentication/authentication_service.ts create mode 100644 x-pack/plugins/security/public/authentication/index.mock.ts create mode 100644 x-pack/plugins/security/public/authentication/index.ts create mode 100644 x-pack/plugins/security/public/mocks.ts diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts index 79ffe58d419bd3..b2cfd826e62079 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -11,6 +11,8 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { UIRoutes } from 'ui/routes'; import { isLeft } from 'fp-ts/lib/Either'; +import { npSetup } from 'ui/new_platform'; +import { SecurityPluginSetup } from '../../../../../../../plugins/security/public'; import { BufferedKibanaServiceCall, KibanaAdapterServiceRefs, KibanaUIConfig } from '../../types'; import { FrameworkAdapter, @@ -58,7 +60,7 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { }; public async waitUntilFrameworkReady(): Promise { - const $injector = await this.onKibanaReady(); + await this.onKibanaReady(); const xpackInfo: any = this.xpackInfoService; let xpackInfoUnpacked: FrameworkInfo; @@ -95,8 +97,10 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { } this.xpackInfo = xpackInfoUnpacked; + const securitySetup = ((npSetup.plugins as unknown) as { security?: SecurityPluginSetup }) + .security; try { - this.shieldUser = await $injector.get('ShieldUser').getCurrent().$promise; + this.shieldUser = (await securitySetup?.authc.getCurrentUser()) || null; const assertUser = RuntimeFrameworkUser.decode(this.shieldUser); if (isLeft(assertUser)) { diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js index aa7f88a62397cc..83446278fdeca8 100755 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js +++ b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js @@ -8,6 +8,7 @@ import React from 'react'; import { render } from 'react-dom'; import { isEmpty } from 'lodash'; import { uiModules } from 'ui/modules'; +import { npSetup } from 'ui/new_platform'; import { toastNotifications } from 'ui/notify'; import { I18nContext } from 'ui/i18n'; import { PipelineEditor } from '../../../../components/pipeline_editor'; @@ -21,7 +22,6 @@ app.directive('pipelineEdit', function($injector) { const pipelineService = $injector.get('pipelineService'); const licenseService = $injector.get('logstashLicenseService'); const kbnUrl = $injector.get('kbnUrl'); - const shieldUser = $injector.get('ShieldUser'); const $route = $injector.get('$route'); return { @@ -32,7 +32,7 @@ app.directive('pipelineEdit', function($injector) { scope.$evalAsync(kbnUrl.change(`/management/logstash/pipelines/${id}/edit`)); const userResource = logstashSecurity.isSecurityEnabled() - ? await shieldUser.getCurrent().$promise + ? await npSetup.plugins.security.authc.getCurrentUser() : null; render( diff --git a/x-pack/legacy/plugins/security/index.js b/x-pack/legacy/plugins/security/index.js index 6ee8b5f8b2b10f..bc403b803b8df0 100644 --- a/x-pack/legacy/plugins/security/index.js +++ b/x-pack/legacy/plugins/security/index.js @@ -28,17 +28,10 @@ export const security = kibana => enabled: Joi.boolean().default(true), cookieName: HANDLED_IN_NEW_PLATFORM, encryptionKey: HANDLED_IN_NEW_PLATFORM, - session: Joi.object({ - idleTimeout: HANDLED_IN_NEW_PLATFORM, - lifespan: HANDLED_IN_NEW_PLATFORM, - }).default(), + session: HANDLED_IN_NEW_PLATFORM, secureCookies: HANDLED_IN_NEW_PLATFORM, loginAssistanceMessage: HANDLED_IN_NEW_PLATFORM, - authorization: Joi.object({ - legacyFallback: Joi.object({ - enabled: Joi.boolean().default(true), // deprecated - }).default(), - }).default(), + authorization: HANDLED_IN_NEW_PLATFORM, audit: Joi.object({ enabled: Joi.boolean().default(false), }).default(), @@ -46,13 +39,6 @@ export const security = kibana => }).default(); }, - deprecations: function({ rename, unused }) { - return [ - unused('authorization.legacyFallback.enabled'), - rename('sessionTimeout', 'session.idleTimeout'), - ]; - }, - uiExports: { chromeNavControls: [], managementSections: ['plugins/security/views/management'], diff --git a/x-pack/legacy/plugins/security/public/lib/api.ts b/x-pack/legacy/plugins/security/public/lib/api.ts index ffa08ca44f3765..c5c6994bf4be36 100644 --- a/x-pack/legacy/plugins/security/public/lib/api.ts +++ b/x-pack/legacy/plugins/security/public/lib/api.ts @@ -5,16 +5,12 @@ */ import { kfetch } from 'ui/kfetch'; -import { AuthenticatedUser, Role, User, EditUser } from '../../common/model'; +import { Role, User, EditUser } from '../../common/model'; const usersUrl = '/internal/security/users'; const rolesUrl = '/api/security/role'; export class UserAPIClient { - public async getCurrentUser(): Promise { - return await kfetch({ pathname: `/internal/security/me` }); - } - public async getUsers(): Promise { return await kfetch({ pathname: usersUrl }); } diff --git a/x-pack/legacy/plugins/security/public/services/shield_user.js b/x-pack/legacy/plugins/security/public/services/shield_user.js deleted file mode 100644 index 14a79f267ca752..00000000000000 --- a/x-pack/legacy/plugins/security/public/services/shield_user.js +++ /dev/null @@ -1,33 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import 'angular-resource'; -import angular from 'angular'; -import { uiModules } from 'ui/modules'; - -const module = uiModules.get('security', ['ngResource']); -module.service('ShieldUser', ($resource, chrome) => { - const baseUrl = chrome.addBasePath('/internal/security/users/:username'); - const ShieldUser = $resource( - baseUrl, - { - username: '@username', - }, - { - changePassword: { - method: 'POST', - url: `${baseUrl}/password`, - transformRequest: ({ password, newPassword }) => angular.toJson({ password, newPassword }), - }, - getCurrent: { - method: 'GET', - url: chrome.addBasePath('/internal/security/me'), - }, - } - ); - - return ShieldUser; -}); diff --git a/x-pack/legacy/plugins/security/public/views/account/account.js b/x-pack/legacy/plugins/security/public/views/account/account.js index db971bd97eab73..70a7b8dce727ec 100644 --- a/x-pack/legacy/plugins/security/public/views/account/account.js +++ b/x-pack/legacy/plugins/security/public/views/account/account.js @@ -6,22 +6,13 @@ import routes from 'ui/routes'; import template from './account.html'; -import '../../services/shield_user'; import { i18n } from '@kbn/i18n'; import { I18nContext } from 'ui/i18n'; +import { npSetup } from 'ui/new_platform'; import { AccountManagementPage } from './components'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -const renderReact = (elem, user) => { - render( - - - , - elem - ); -}; - routes.when('/account', { template, k7Breadcrumbs: () => [ @@ -31,13 +22,8 @@ routes.when('/account', { }), }, ], - resolve: { - user(ShieldUser) { - return ShieldUser.getCurrent().$promise; - }, - }, controllerAs: 'accountController', - controller($scope, $route) { + controller($scope) { $scope.$on('$destroy', () => { const elem = document.getElementById('userProfileReactRoot'); if (elem) { @@ -45,8 +31,12 @@ routes.when('/account', { } }); $scope.$$postDigest(() => { - const elem = document.getElementById('userProfileReactRoot'); - renderReact(elem, $route.current.locals.user); + render( + + + , + document.getElementById('userProfileReactRoot') + ); }); }, }); diff --git a/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.test.tsx b/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.test.tsx index 176b05f455439b..366842e58e9e4a 100644 --- a/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.test.tsx +++ b/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.test.tsx @@ -4,8 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { act } from '@testing-library/react'; +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; +import { securityMock } from '../../../../../../../plugins/security/public/mocks'; import { AccountManagementPage } from './account_management_page'; +import { AuthenticatedUser } from '../../../../common/model'; jest.mock('ui/kfetch'); @@ -32,10 +35,24 @@ const createUser = ({ withFullName = true, withEmail = true, realm = 'native' }: }; }; +function getSecuritySetupMock({ currentUser }: { currentUser: AuthenticatedUser }) { + const securitySetupMock = securityMock.createSetup(); + securitySetupMock.authc.getCurrentUser.mockResolvedValue(currentUser); + return securitySetupMock; +} + describe('', () => { - it(`displays users full name, username, and email address`, () => { + it(`displays users full name, username, and email address`, async () => { const user = createUser(); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(wrapper.find('EuiText[data-test-subj="userDisplayName"]').text()).toEqual( user.full_name ); @@ -43,28 +60,60 @@ describe('', () => { expect(wrapper.find('[data-test-subj="email"]').text()).toEqual(user.email); }); - it(`displays username when full_name is not provided`, () => { + it(`displays username when full_name is not provided`, async () => { const user = createUser({ withFullName: false }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(wrapper.find('EuiText[data-test-subj="userDisplayName"]').text()).toEqual(user.username); }); - it(`displays a placeholder when no email address is provided`, () => { + it(`displays a placeholder when no email address is provided`, async () => { const user = createUser({ withEmail: false }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(wrapper.find('[data-test-subj="email"]').text()).toEqual('no email address'); }); - it(`displays change password form for users in the native realm`, () => { + it(`displays change password form for users in the native realm`, async () => { const user = createUser(); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(wrapper.find('EuiFieldText[data-test-subj="currentPassword"]')).toHaveLength(1); expect(wrapper.find('EuiFieldText[data-test-subj="newPassword"]')).toHaveLength(1); }); - it(`does not display change password form for users in the saml realm`, () => { + it(`does not display change password form for users in the saml realm`, async () => { const user = createUser({ realm: 'saml' }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect(wrapper.find('EuiFieldText[data-test-subj="currentPassword"]')).toHaveLength(0); expect(wrapper.find('EuiFieldText[data-test-subj="newPassword"]')).toHaveLength(0); }); diff --git a/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.tsx b/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.tsx index 2ed057ad73a123..6abee73e0b3535 100644 --- a/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.tsx +++ b/x-pack/legacy/plugins/security/public/views/account/components/account_management_page.tsx @@ -4,29 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ import { EuiPage, EuiPageBody, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { SecurityPluginSetup } from '../../../../../../../plugins/security/public'; import { getUserDisplayName, AuthenticatedUser } from '../../../../common/model'; import { ChangePassword } from './change_password'; import { PersonalInfo } from './personal_info'; interface Props { - user: AuthenticatedUser; + securitySetup: SecurityPluginSetup; } -export const AccountManagementPage: React.FC = props => ( - - - - -

{getUserDisplayName(props.user)}

-
+export const AccountManagementPage = (props: Props) => { + const [currentUser, setCurrentUser] = useState(null); + useEffect(() => { + props.securitySetup.authc.getCurrentUser().then(setCurrentUser); + }, [props]); - + if (!currentUser) { + return null; + } - + return ( + + + + +

{getUserDisplayName(currentUser)}

+
- -
-
-
-); + + + + + +
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js b/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js index 09c612526918fe..27c9beb4ba8284 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/index.js @@ -11,10 +11,10 @@ import { kfetch } from 'ui/kfetch'; import { fatalError, toastNotifications } from 'ui/notify'; import { npStart } from 'ui/new_platform'; import template from 'plugins/security/views/management/edit_role/edit_role.html'; -import 'plugins/security/services/shield_user'; import 'plugins/security/services/shield_role'; import 'plugins/security/services/shield_indices'; import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; +import { UserAPIClient } from '../../../lib/api'; import { ROLES_PATH, CLONE_ROLES_PATH, EDIT_ROLES_PATH } from '../management_urls'; import { getEditRoleBreadcrumbs, getCreateRoleBreadcrumbs } from '../breadcrumbs'; @@ -69,9 +69,8 @@ const routeDefinition = action => ({ return role.then(res => res.toJSON()); }, - users(ShieldUser) { - // $promise is used here because the result is an ngResource, not a promise itself - return ShieldUser.query().$promise.then(users => _.map(users, 'username')); + users() { + return new UserAPIClient().getUsers().then(users => _.map(users, 'username')); }, indexPatterns() { return npStart.plugins.data.indexPatterns.getTitles(); diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx index 5c71d0da3954af..639646ce48e224 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx @@ -4,38 +4,42 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { act } from '@testing-library/react'; +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; import { EditUserPage } from './edit_user_page'; import React from 'react'; +import { securityMock } from '../../../../../../../../plugins/security/public/mocks'; import { UserAPIClient } from '../../../../lib/api'; import { User, Role } from '../../../../../common/model'; import { ReactWrapper } from 'enzyme'; +import { mockAuthenticatedUser } from '../../../../../../../../plugins/security/common/model/authenticated_user.mock'; jest.mock('ui/kfetch'); -const buildClient = () => { - const apiClient = new UserAPIClient(); +const createUser = (username: string) => { + const user: User = { + username, + full_name: 'my full name', + email: 'foo@bar.com', + roles: ['idk', 'something'], + enabled: true, + }; - const createUser = (username: string) => { - const user: User = { - username, - full_name: 'my full name', - email: 'foo@bar.com', - roles: ['idk', 'something'], - enabled: true, + if (username === 'reserved_user') { + user.metadata = { + _reserved: true, }; + } - if (username === 'reserved_user') { - user.metadata = { - _reserved: true, - }; - } + return user; +}; - return Promise.resolve(user); - }; +const buildClient = () => { + const apiClient = new UserAPIClient(); - apiClient.getUser = jest.fn().mockImplementation(createUser); - apiClient.getCurrentUser = jest.fn().mockImplementation(() => createUser('current_user')); + apiClient.getUser = jest + .fn() + .mockImplementation(async (username: string) => createUser(username)); apiClient.getRoles = jest.fn().mockImplementation(() => { return Promise.resolve([ @@ -63,6 +67,14 @@ const buildClient = () => { return apiClient; }; +function buildSecuritySetup() { + const securitySetupMock = securityMock.createSetup(); + securitySetupMock.authc.getCurrentUser.mockResolvedValue( + mockAuthenticatedUser(createUser('current_user')) + ); + return securitySetupMock; +} + function expectSaveButton(wrapper: ReactWrapper) { expect(wrapper.find('EuiButton[data-test-subj="userFormSaveButton"]')).toHaveLength(1); } @@ -74,10 +86,12 @@ function expectMissingSaveButton(wrapper: ReactWrapper) { describe('EditUserPage', () => { it('allows reserved users to be viewed', async () => { const apiClient = buildClient(); + const securitySetup = buildSecuritySetup(); const wrapper = mountWithIntl( path} intl={null as any} /> @@ -86,17 +100,19 @@ describe('EditUserPage', () => { await waitForRender(wrapper); expect(apiClient.getUser).toBeCalledTimes(1); - expect(apiClient.getCurrentUser).toBeCalledTimes(1); + expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(1); expectMissingSaveButton(wrapper); }); it('allows new users to be created', async () => { const apiClient = buildClient(); + const securitySetup = buildSecuritySetup(); const wrapper = mountWithIntl( path} intl={null as any} /> @@ -105,17 +121,19 @@ describe('EditUserPage', () => { await waitForRender(wrapper); expect(apiClient.getUser).toBeCalledTimes(0); - expect(apiClient.getCurrentUser).toBeCalledTimes(0); + expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(0); expectSaveButton(wrapper); }); it('allows existing users to be edited', async () => { const apiClient = buildClient(); + const securitySetup = buildSecuritySetup(); const wrapper = mountWithIntl( path} intl={null as any} /> @@ -124,16 +142,15 @@ describe('EditUserPage', () => { await waitForRender(wrapper); expect(apiClient.getUser).toBeCalledTimes(1); - expect(apiClient.getCurrentUser).toBeCalledTimes(1); + expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(1); expectSaveButton(wrapper); }); }); async function waitForRender(wrapper: ReactWrapper) { - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - wrapper.update(); + await act(async () => { + await nextTick(); + wrapper.update(); + }); } diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx index 91f5f048adc6d0..bbffe07485f8dc 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx @@ -28,6 +28,7 @@ import { } from '@elastic/eui'; import { toastNotifications } from 'ui/notify'; import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react'; +import { SecurityPluginSetup } from '../../../../../../../../plugins/security/public'; import { UserValidator, UserValidationResult } from '../../../../lib/validate_user'; import { User, EditUser, Role } from '../../../../../common/model'; import { USERS_PATH } from '../../../../views/management/management_urls'; @@ -40,6 +41,7 @@ interface Props { intl: InjectedIntl; changeUrl: (path: string) => void; apiClient: UserAPIClient; + securitySetup: SecurityPluginSetup; } interface State { @@ -82,7 +84,7 @@ class EditUserPageUI extends Component { } public async componentDidMount() { - const { username, apiClient } = this.props; + const { username, apiClient, securitySetup } = this.props; let { user, currentUser } = this.state; if (username) { try { @@ -91,7 +93,7 @@ class EditUserPageUI extends Component { password: '', confirmPassword: '', }; - currentUser = await apiClient.getCurrentUser(); + currentUser = await securitySetup.authc.getCurrentUser(); } catch (err) { toastNotifications.addDanger({ title: this.props.intl.formatMessage({ diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/edit_user.js b/x-pack/legacy/plugins/security/public/views/management/edit_user/edit_user.js index bd9d6f2b1ca35c..ab218022c6ee64 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_user/edit_user.js +++ b/x-pack/legacy/plugins/security/public/views/management/edit_user/edit_user.js @@ -7,7 +7,6 @@ import routes from 'ui/routes'; import template from 'plugins/security/views/management/edit_user/edit_user.html'; import 'angular-resource'; import 'ui/angular_ui_select'; -import 'plugins/security/services/shield_user'; import 'plugins/security/services/shield_role'; import { EDIT_USERS_PATH } from '../management_urls'; import { EditUserPage } from './components'; @@ -15,12 +14,18 @@ import { UserAPIClient } from '../../../lib/api'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nContext } from 'ui/i18n'; +import { npSetup } from 'ui/new_platform'; import { getEditUserBreadcrumbs, getCreateUserBreadcrumbs } from '../breadcrumbs'; const renderReact = (elem, changeUrl, username) => { render( - + , elem ); diff --git a/x-pack/legacy/plugins/security/public/views/management/management.js b/x-pack/legacy/plugins/security/public/views/management/management.js index db2175e91c5de9..59da63abbb83ff 100644 --- a/x-pack/legacy/plugins/security/public/views/management/management.js +++ b/x-pack/legacy/plugins/security/public/views/management/management.js @@ -13,10 +13,10 @@ import 'plugins/security/views/management/edit_user/edit_user'; import 'plugins/security/views/management/edit_role/index'; import routes from 'ui/routes'; import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import '../../services/shield_user'; import { ROLES_PATH, USERS_PATH, API_KEYS_PATH } from './management_urls'; import { management } from 'ui/management'; +import { npSetup } from 'ui/new_platform'; import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; @@ -36,7 +36,7 @@ routes }) .defaults(/\/management/, { resolve: { - securityManagementSection: function(ShieldUser) { + securityManagementSection: function() { const showSecurityLinks = xpackInfo.get('features.security.showLinks'); function deregisterSecurity() { @@ -93,12 +93,11 @@ routes if (!showSecurityLinks) { deregisterSecurity(); } else { - // getCurrent will reject if there is no authenticated user, so we prevent them from seeing the security - // management screens - // - // $promise is used here because the result is an ngResource, not a promise itself - return ShieldUser.getCurrent() - .$promise.then(ensureSecurityRegistered) + // getCurrentUser will reject if there is no authenticated user, so we prevent them from + // seeing the security management screens. + return npSetup.plugins.security.authc + .getCurrentUser() + .then(ensureSecurityRegistered) .catch(deregisterSecurity); } }, diff --git a/x-pack/legacy/plugins/security/public/views/management/users_grid/users.js b/x-pack/legacy/plugins/security/public/views/management/users_grid/users.js index a7115f449ebfd5..8d4e0526251d76 100644 --- a/x-pack/legacy/plugins/security/public/views/management/users_grid/users.js +++ b/x-pack/legacy/plugins/security/public/views/management/users_grid/users.js @@ -8,7 +8,6 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import routes from 'ui/routes'; import template from 'plugins/security/views/management/users_grid/users.html'; -import 'plugins/security/services/shield_user'; import { SECURITY_PATH, USERS_PATH } from '../management_urls'; import { UsersListPage } from './components'; import { UserAPIClient } from '../../../lib/api'; diff --git a/x-pack/legacy/plugins/security/public/views/overwritten_session/overwritten_session.tsx b/x-pack/legacy/plugins/security/public/views/overwritten_session/overwritten_session.tsx index 76088443212b24..fb39c517e1c2ca 100644 --- a/x-pack/legacy/plugins/security/public/views/overwritten_session/overwritten_session.tsx +++ b/x-pack/legacy/plugins/security/public/views/overwritten_session/overwritten_session.tsx @@ -10,36 +10,40 @@ import React from 'react'; import { render } from 'react-dom'; import chrome from 'ui/chrome'; import { I18nContext } from 'ui/i18n'; +import { npSetup } from 'ui/new_platform'; +import { SecurityPluginSetup } from '../../../../../../plugins/security/public'; import { AuthenticatedUser } from '../../../common/model'; import { AuthenticationStatePage } from '../../components/authentication_state_page'; chrome .setVisible(false) .setRootTemplate('
') - .setRootController('overwritten_session', ($scope: any, ShieldUser: any) => { + .setRootController('overwritten_session', ($scope: any) => { $scope.$$postDigest(() => { - ShieldUser.getCurrent().$promise.then((user: AuthenticatedUser) => { - const overwrittenSessionPage = ( - - - } - > - - - - - - ); - render(overwrittenSessionPage, document.getElementById('reactOverwrittenSessionRoot')); - }); + ((npSetup.plugins as unknown) as { security: SecurityPluginSetup }).security.authc + .getCurrentUser() + .then((user: AuthenticatedUser) => { + const overwrittenSessionPage = ( + + + } + > + + + + + + ); + render(overwrittenSessionPage, document.getElementById('reactOverwrittenSessionRoot')); + }); }); }); diff --git a/x-pack/plugins/security/public/authentication/authentication_service.ts b/x-pack/plugins/security/public/authentication/authentication_service.ts new file mode 100644 index 00000000000000..23c45c88e563a1 --- /dev/null +++ b/x-pack/plugins/security/public/authentication/authentication_service.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { HttpSetup } from 'src/core/public'; +import { AuthenticatedUser } from '../../common/model'; + +interface SetupParams { + http: HttpSetup; +} + +export interface AuthenticationServiceSetup { + /** + * Returns currently authenticated user and throws if current user isn't authenticated. + */ + getCurrentUser: () => Promise; +} + +export class AuthenticationService { + public setup({ http }: SetupParams): AuthenticationServiceSetup { + return { + async getCurrentUser() { + return (await http.get('/internal/security/me', { + headers: { 'kbn-system-api': true }, + })) as AuthenticatedUser; + }, + }; + } +} diff --git a/x-pack/plugins/security/public/authentication/index.mock.ts b/x-pack/plugins/security/public/authentication/index.mock.ts new file mode 100644 index 00000000000000..c8d77a5b62c6f2 --- /dev/null +++ b/x-pack/plugins/security/public/authentication/index.mock.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AuthenticationServiceSetup } from './authentication_service'; + +export const authenticationMock = { + createSetup: (): jest.Mocked => ({ + getCurrentUser: jest.fn(), + }), +}; diff --git a/x-pack/plugins/security/public/authentication/index.ts b/x-pack/plugins/security/public/authentication/index.ts new file mode 100644 index 00000000000000..a55f4d7bb95b38 --- /dev/null +++ b/x-pack/plugins/security/public/authentication/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { AuthenticationService, AuthenticationServiceSetup } from './authentication_service'; diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index dc34fcbbe7d1e6..336ec37d76a1b9 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -6,7 +6,10 @@ import { PluginInitializer } from 'src/core/public'; import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin'; + +export { SecurityPluginSetup, SecurityPluginStart }; export { SessionInfo } from './types'; +export { AuthenticatedUser } from '../common/model'; export const plugin: PluginInitializer = () => new SecurityPlugin(); diff --git a/x-pack/plugins/security/public/mocks.ts b/x-pack/plugins/security/public/mocks.ts new file mode 100644 index 00000000000000..3c0c59d10abd1a --- /dev/null +++ b/x-pack/plugins/security/public/mocks.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { authenticationMock } from './authentication/index.mock'; +import { createSessionTimeoutMock } from './session/session_timeout.mock'; + +function createSetupMock() { + return { + authc: authenticationMock.createSetup(), + sessionTimeout: createSessionTimeoutMock(), + }; +} + +export const securityMock = { + createSetup: createSetupMock, +}; diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts index 3879d611d46ebf..a9a89ee05f561e 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts @@ -10,6 +10,8 @@ import { ILicense } from '../../../licensing/public'; import { SecurityNavControlService } from '.'; import { SecurityLicenseService } from '../../common/licensing'; import { nextTick } from 'test_utils/enzyme_helpers'; +import { securityMock } from '../mocks'; +import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; const validLicense = { isAvailable: true, @@ -29,13 +31,17 @@ describe('SecurityNavControlService', () => { const license$ = new BehaviorSubject(validLicense); const navControlService = new SecurityNavControlService(); + const mockSecuritySetup = securityMock.createSetup(); + mockSecuritySetup.authc.getCurrentUser.mockResolvedValue( + mockAuthenticatedUser({ username: 'some-user', full_name: undefined }) + ); navControlService.setup({ securityLicense: new SecurityLicenseService().setup({ license$ }).license, + authc: mockSecuritySetup.authc, }); const coreStart = coreMock.createStart(); coreStart.chrome.navControls.registerRight = jest.fn(); - coreStart.http.get.mockResolvedValue({ username: 'some-user' }); navControlService.start({ core: coreStart }); expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(1); @@ -93,6 +99,7 @@ describe('SecurityNavControlService', () => { const navControlService = new SecurityNavControlService(); navControlService.setup({ securityLicense: new SecurityLicenseService().setup({ license$ }).license, + authc: securityMock.createSetup().authc, }); const coreStart = coreMock.createStart(); @@ -111,6 +118,7 @@ describe('SecurityNavControlService', () => { const navControlService = new SecurityNavControlService(); navControlService.setup({ securityLicense: new SecurityLicenseService().setup({ license$ }).license, + authc: securityMock.createSetup().authc, }); const coreStart = coreMock.createStart(); @@ -126,6 +134,7 @@ describe('SecurityNavControlService', () => { const navControlService = new SecurityNavControlService(); navControlService.setup({ securityLicense: new SecurityLicenseService().setup({ license$ }).license, + authc: securityMock.createSetup().authc, }); const coreStart = coreMock.createStart(); @@ -146,6 +155,7 @@ describe('SecurityNavControlService', () => { const navControlService = new SecurityNavControlService(); navControlService.setup({ securityLicense: new SecurityLicenseService().setup({ license$ }).license, + authc: securityMock.createSetup().authc, }); const coreStart = coreMock.createStart(); diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx index aeeb84219c937d..153e7112dc95b3 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx @@ -9,11 +9,12 @@ import { CoreStart } from 'src/core/public'; import ReactDOM from 'react-dom'; import React from 'react'; import { SecurityLicense } from '../../common/licensing'; -import { AuthenticatedUser } from '../../common/model'; import { SecurityNavControl } from './nav_control_component'; +import { AuthenticationServiceSetup } from '../authentication'; interface SetupDeps { securityLicense: SecurityLicense; + authc: AuthenticationServiceSetup; } interface StartDeps { @@ -22,13 +23,15 @@ interface StartDeps { export class SecurityNavControlService { private securityLicense!: SecurityLicense; + private authc!: AuthenticationServiceSetup; private navControlRegistered!: boolean; private securityFeaturesSubscription?: Subscription; - public setup({ securityLicense }: SetupDeps) { + public setup({ securityLicense, authc }: SetupDeps) { this.securityLicense = securityLicense; + this.authc = authc; } public start({ core }: StartDeps) { @@ -38,14 +41,8 @@ export class SecurityNavControlService { const shouldRegisterNavControl = !isAnonymousPath && showLinks && !this.navControlRegistered; - if (shouldRegisterNavControl) { - const user = core.http.get('/internal/security/me', { - headers: { - 'kbn-system-api': true, - }, - }) as Promise; - this.registerSecurityNavControl(core, user); + this.registerSecurityNavControl(core); } } ); @@ -60,16 +57,16 @@ export class SecurityNavControlService { } private registerSecurityNavControl( - core: Pick, - user: Promise + core: Pick ) { + const currentUserPromise = this.authc.getCurrentUser(); core.chrome.navControls.registerRight({ order: 2000, mount: (el: HTMLElement) => { const I18nContext = core.i18n.Context; const props = { - user, + user: currentUserPromise, editProfileUrl: core.http.basePath.prepend('/app/kibana#/account'), logoutUrl: core.http.basePath.prepend(`/logout`), }; diff --git a/x-pack/plugins/security/public/plugin.ts b/x-pack/plugins/security/public/plugin.ts index 0f10f9d89f25a2..50e0b838c750fc 100644 --- a/x-pack/plugins/security/public/plugin.ts +++ b/x-pack/plugins/security/public/plugin.ts @@ -9,18 +9,20 @@ import { LicensingPluginSetup } from '../../licensing/public'; import { SessionExpired, SessionTimeout, + ISessionTimeout, SessionTimeoutHttpInterceptor, UnauthorizedResponseHttpInterceptor, } from './session'; import { SecurityLicenseService } from '../common/licensing'; import { SecurityNavControlService } from './nav_control'; +import { AuthenticationService } from './authentication'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; } export class SecurityPlugin implements Plugin { - private sessionTimeout!: SessionTimeout; + private sessionTimeout!: ISessionTimeout; private navControlService!: SecurityNavControlService; @@ -43,12 +45,15 @@ export class SecurityPlugin implements Plugin; private sessionInfo?: SessionInfo; private fetchTimer?: number; diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index b3f96497b0538b..4f1c25702ae974 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -8,7 +8,6 @@ import crypto from 'crypto'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { schema, Type, TypeOf } from '@kbn/config-schema'; -import { duration } from 'moment'; import { PluginInitializerContext } from '../../../../src/core/server'; export type ConfigType = ReturnType extends Observable @@ -35,7 +34,6 @@ export const ConfigSchema = schema.object( schema.maybe(schema.string({ minLength: 32 })), schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) ), - sessionTimeout: schema.maybe(schema.nullable(schema.number())), // DEPRECATED session: schema.object({ idleTimeout: schema.nullable(schema.duration()), lifespan: schema.nullable(schema.duration()), @@ -88,22 +86,11 @@ export function createConfig$(context: PluginInitializerContext, isTLSEnabled: b secureCookies = true; } - // "sessionTimeout" is deprecated and replaced with "session.idleTimeout" - // however, NP does not yet have a mechanism to automatically rename deprecated keys - // for the time being, we'll do it manually: - const deprecatedSessionTimeout = - typeof config.sessionTimeout === 'number' ? duration(config.sessionTimeout) : null; - const val = { + return { ...config, encryptionKey, secureCookies, - session: { - ...config.session, - idleTimeout: config.session.idleTimeout || deprecatedSessionTimeout, - }, }; - delete val.sessionTimeout; // DEPRECATED - return val; }) ); } diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index e189b71345ffc9..33f554be5caa3b 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -4,9 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from '../../../../src/core/server'; +import { TypeOf } from '@kbn/config-schema'; +import { + PluginConfigDescriptor, + PluginInitializer, + PluginInitializerContext, + RecursiveReadonly, +} from '../../../../src/core/server'; import { ConfigSchema } from './config'; -import { Plugin } from './plugin'; +import { Plugin, PluginSetupContract, PluginSetupDependencies } from './plugin'; // These exports are part of public Security plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. @@ -17,8 +23,17 @@ export { InvalidateAPIKeyParams, InvalidateAPIKeyResult, } from './authentication'; -export { PluginSetupContract } from './plugin'; +export { PluginSetupContract }; -export const config = { schema: ConfigSchema }; -export const plugin = (initializerContext: PluginInitializerContext) => - new Plugin(initializerContext); +export const config: PluginConfigDescriptor> = { + schema: ConfigSchema, + deprecations: ({ rename, unused }) => [ + rename('sessionTimeout', 'session.idleTimeout'), + unused('authorization.legacyFallback.enabled'), + ], +}; +export const plugin: PluginInitializer< + RecursiveReadonly, + void, + PluginSetupDependencies +> = (initializerContext: PluginInitializerContext) => new Plugin(initializerContext); diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index cdd2a024310bbc..9c4b01f94ef4df 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -110,10 +110,7 @@ export class Plugin { this.logger = this.initializerContext.logger.get(); } - public async setup( - core: CoreSetup, - { features, licensing }: PluginSetupDependencies - ): Promise> { + public async setup(core: CoreSetup, { features, licensing }: PluginSetupDependencies) { const [config, legacyConfig] = await combineLatest([ createConfig$(this.initializerContext, core.http.isTlsEnabled), this.initializerContext.config.legacy.globalConfig$, @@ -169,7 +166,7 @@ export class Plugin { csp: core.http.csp, }); - return deepFreeze({ + return deepFreeze({ authc, authz: { From 5b2a188c4362211798df998e990e2047575ee309 Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Mon, 6 Jan 2020 10:55:15 +0000 Subject: [PATCH 2/3] [Dashboard] Empty screen redesign (#53681) * Edit screen redesign * Edit screen redesign * Redesign view screen * Redesign view screen * Fixing type failure, and functional test * Updating failing functional tests * update dashboard empty styles * i18n fix * Updating failing snapshot Co-authored-by: Ryan Keairns Co-authored-by: Elastic Machine --- .../dashboard_empty_screen.test.tsx.snap | 512 ++++++++++-------- .../__tests__/dashboard_empty_screen.test.tsx | 5 + .../public/dashboard/_dashboard_app.scss | 28 +- .../np_ready/dashboard_app_controller.tsx | 4 +- .../np_ready/dashboard_empty_screen.tsx | 80 +-- .../dashboard_empty_screen_constants.tsx | 60 +- .../home/assets/welcome_graphic_dark_2x.png | Bin 0 -> 53603 bytes .../home/assets/welcome_graphic_light_2x.png | Bin 0 -> 53122 bytes .../apps/dashboard/empty_dashboard.js | 8 +- .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - .../feature_controls/dashboard_security.ts | 2 +- .../feature_controls/dashboard_spaces.ts | 2 +- 13 files changed, 402 insertions(+), 305 deletions(-) create mode 100644 src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_dark_2x.png create mode 100644 src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_light_2x.png diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap index d48e34b2e48370..f611ec978b6b36 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -2,6 +2,31 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` - -
- -
+ - - -
+ - - - - - - -
- - -
-

- This dashboard is empty. Let’s fill it up! -

-
-
- -
- - -
-

- Click the - - - - button in the menu bar above to add a visualization to the dashboard. -

-
-
- -
- -

- - - -

-
- - -
-
-
-
+ Add an existing + + + +   + + or new object to this dashboard +

+
+ + + + +
+ +

+ + + +

+
@@ -373,6 +361,31 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` exports[`DashboardEmptyScreen renders correctly without visualize paragraph 1`] = `
@@ -581,59 +630,48 @@ exports[`DashboardEmptyScreen renders correctly without visualize paragraph 1`] className="euiPageBody" >
- - - - - - -
- + +
-

This dashboard is empty. Let’s fill it up! -

+

- -
-

- Click the - + - - - button in the menu bar above to start working on your new dashboard. -

-
-
+

+ Click + +   + + + + + +   + + in the menu bar above to start adding panels. +

+
+ +
+ +
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx index 1c450879ee5530..381ced2efd8e3e 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/dashboard_empty_screen.test.tsx @@ -24,11 +24,16 @@ import { } from '../np_ready/dashboard_empty_screen'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; +import { coreMock } from '../../../../../../core/public/mocks'; describe('DashboardEmptyScreen', () => { + const setupMock = coreMock.createSetup(); + const defaultProps = { showLinkToVisualize: true, onLinkClick: jest.fn(), + uiSettings: setupMock.uiSettings, + http: setupMock.http, }; function mountComponent(props?: DashboardEmptyScreenProps) { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss index d9eadf6c0e37d0..03a8a07d6b17da 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss +++ b/src/legacy/core_plugins/kibana/public/dashboard/_dashboard_app.scss @@ -6,5 +6,31 @@ .dshStartScreen { text-align: center; - padding: $euiSizeS; +} + +.dshStartScreen__pageContent { + padding: $euiSizeXXL; +} + +.dshStartScreen__panelDesc { + max-width: 260px; + margin: 0 auto; +} + +.dshEmptyWidget { + border: $euiBorderThin; + border-style: dashed; + border-radius: $euiBorderRadius; + padding: $euiSizeXXL * 2; + max-width: 400px; + margin-left: $euiSizeS; + text-align: center; +} + +.dshEmptyWidget { + border: 2px dashed $euiColorLightShade; + padding: 4 * $euiSize; + max-width: 20em; + margin-left: 10px; + text-align: center; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index 08637174c8cec9..8fcc7e4c263210 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -123,7 +123,7 @@ export class DashboardAppController { timefilter: { timefilter }, }, }, - core: { notifications, overlays, chrome, injectedMetadata, uiSettings, savedObjects }, + core: { notifications, overlays, chrome, injectedMetadata, uiSettings, savedObjects, http }, }: DashboardAppControllerDependencies) { new FilterStateManager(globalState, getAppState, filterManager); const queryFilter = filterManager; @@ -197,6 +197,8 @@ export class DashboardAppController { const emptyScreenProps: DashboardEmptyScreenProps = { onLinkClick: shouldShowEditHelp ? $scope.showAddPanel : $scope.enterEditMode, showLinkToVisualize: shouldShowEditHelp, + uiSettings, + http, }; if (shouldShowEditHelp) { emptyScreenProps.onVisualizeClick = addVisualization; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen.tsx index 2fc78d64d0a0cd..ae5319c560ab95 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen.tsx @@ -19,94 +19,110 @@ import React from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { - EuiIcon, EuiLink, EuiSpacer, EuiPageContent, EuiPageBody, EuiPage, + EuiImage, EuiText, EuiButton, } from '@elastic/eui'; +import { IUiSettingsClient, HttpStart } from 'kibana/public'; import * as constants from './dashboard_empty_screen_constants'; export interface DashboardEmptyScreenProps { showLinkToVisualize: boolean; onLinkClick: () => void; onVisualizeClick?: () => void; + uiSettings: IUiSettingsClient; + http: HttpStart; } export function DashboardEmptyScreen({ showLinkToVisualize, onLinkClick, onVisualizeClick, + uiSettings, + http, }: DashboardEmptyScreenProps) { + const IS_DARK_THEME = uiSettings.get('theme:darkMode'); + const emptyStateGraphicURL = IS_DARK_THEME + ? '/plugins/kibana/home/assets/welcome_graphic_dark_2x.png' + : '/plugins/kibana/home/assets/welcome_graphic_light_2x.png'; const linkToVisualizeParagraph = (

{constants.createNewVisualizationButton}

); const paragraph = ( - description1: string, + description1: string | null, description2: string, linkText: string, ariaLabel: string, dataTestSubj?: string ) => { return ( - +

{description1} + {description1 &&  } {linkText} +   {description2}

); }; - const addVisualizationParagraph = ( - - {paragraph( - constants.addVisualizationDescription1, - constants.addVisualizationDescription2, - constants.addVisualizationLinkText, - constants.addVisualizationLinkAriaLabel, - 'emptyDashboardAddPanelButton' - )} - - {linkToVisualizeParagraph} - - ); const enterEditModeParagraph = paragraph( constants.howToStartWorkingOnNewDashboardDescription1, constants.howToStartWorkingOnNewDashboardDescription2, constants.howToStartWorkingOnNewDashboardEditLinkText, constants.howToStartWorkingOnNewDashboardEditLinkAriaLabel ); - return ( - - - - - - - -

{constants.fillDashboardTitle}

-
- - {showLinkToVisualize ? addVisualizationParagraph : enterEditModeParagraph} -
-
-
-
+ const enterViewModeParagraph = paragraph( + null, + constants.addNewVisualizationDescription, + constants.addExistingVisualizationLinkText, + constants.addExistingVisualizationLinkAriaLabel + ); + const viewMode = ( + + + + + +

{constants.fillDashboardTitle}

+
+ +
{enterEditModeParagraph}
+
+
+
+ ); + const editMode = ( +
+ {enterViewModeParagraph} + + {linkToVisualizeParagraph} +
); + return {showLinkToVisualize ? editMode : viewMode}; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen_constants.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen_constants.tsx index 03004f6270fef9..513e6cb685a7ac 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen_constants.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_empty_screen_constants.tsx @@ -19,40 +19,20 @@ import { i18n } from '@kbn/i18n'; -export const addVisualizationDescription1: string = i18n.translate( - 'kbn.dashboard.addVisualizationDescription1', - { - defaultMessage: 'Click the ', - } -); -export const addVisualizationDescription2: string = i18n.translate( - 'kbn.dashboard.addVisualizationDescription2', - { - defaultMessage: ' button in the menu bar above to add a visualization to the dashboard.', - } -); -export const addVisualizationLinkText: string = i18n.translate( - 'kbn.dashboard.addVisualizationLinkText', - { - defaultMessage: 'Add', - } -); -export const addVisualizationLinkAriaLabel: string = i18n.translate( - 'kbn.dashboard.addVisualizationLinkAriaLabel', - { - defaultMessage: 'Add visualization', - } -); +/** VIEW MODE CONSTANTS **/ +export const fillDashboardTitle: string = i18n.translate('kbn.dashboard.fillDashboardTitle', { + defaultMessage: 'This dashboard is empty. Let\u2019s fill it up!', +}); export const howToStartWorkingOnNewDashboardDescription1: string = i18n.translate( 'kbn.dashboard.howToStartWorkingOnNewDashboardDescription1', { - defaultMessage: 'Click the ', + defaultMessage: 'Click', } ); export const howToStartWorkingOnNewDashboardDescription2: string = i18n.translate( 'kbn.dashboard.howToStartWorkingOnNewDashboardDescription2', { - defaultMessage: ' button in the menu bar above to start working on your new dashboard.', + defaultMessage: 'in the menu bar above to start adding panels.', } ); export const howToStartWorkingOnNewDashboardEditLinkText: string = i18n.translate( @@ -67,13 +47,23 @@ export const howToStartWorkingOnNewDashboardEditLinkAriaLabel: string = i18n.tra defaultMessage: 'Edit dashboard', } ); -export const fillDashboardTitle: string = i18n.translate('kbn.dashboard.fillDashboardTitle', { - defaultMessage: 'This dashboard is empty. Let\u2019s fill it up!', -}); -export const visualizeAppLinkTest: string = i18n.translate( - 'kbn.dashboard.visitVisualizeAppLinkText', +/** EDIT MODE CONSTANTS **/ +export const addExistingVisualizationLinkText: string = i18n.translate( + 'kbn.dashboard.addExistingVisualizationLinkText', + { + defaultMessage: 'Add an existing', + } +); +export const addExistingVisualizationLinkAriaLabel: string = i18n.translate( + 'kbn.dashboard.addVisualizationLinkAriaLabel', + { + defaultMessage: 'Add an existing visualization', + } +); +export const addNewVisualizationDescription: string = i18n.translate( + 'kbn.dashboard.addNewVisualizationText', { - defaultMessage: 'visit the Visualize app', + defaultMessage: 'or new object to this dashboard', } ); export const createNewVisualizationButton: string = i18n.translate( @@ -82,3 +72,9 @@ export const createNewVisualizationButton: string = i18n.translate( defaultMessage: 'Create new', } ); +export const createNewVisualizationButtonAriaLabel: string = i18n.translate( + 'kbn.dashboard.createNewVisualizationButtonAriaLabel', + { + defaultMessage: 'Create new visualization button', + } +); diff --git a/src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_dark_2x.png b/src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_dark_2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8f551c54bd5527bcd9f3c6848ec550b4324f474b GIT binary patch literal 53603 zcmY&z<)mwvzX)?4q7 ztR#2tojY>o%-Q?wiBM6J!9XQJefRDihMcUV+PinKGw_!t5X>n`tl2y|w zNJ-EMp}SPW@zlN4j?XD z4gQPuwu^%8l|h&hx10Y*`E8zP8ze5d*MS%U5Jv`vaA6^E0ss5SA_}7jy#Rd(O+^&< zUm0Ky7H{T%w>7-`|86@GD(8`k^fK~<-X?(pEh=~zcq|SFh>u()9Qeo}pYZLsdrqPN zL(o~6;jsT-U2(ls&8!LA2kBzSK=Ym4(0r-nt+({I4#;9whW~wk^_LS*3jFwe34g(F zf`8A$-&*8{Z|taDm7~f#xuE~QHIWWWkcn~~)l-)${4EbY9D5&sOH@q_42kO!huP$R zXs(@-B#b@sBpv3m9=<7LB}Z#1gxqu%$`6YN;nf*YBc-9r&`Iv0IKc>J-y(3&@#8SW zFCeo~LMsRiAixxt{TASCq<`fh#IK7zy%+UUZT7|AZLwVN-*CXeGR=g zZV8di!FzXwr~TkT$-U7vU+aNYMarwZOXv&ZgnQ`3p$!mwb!$DBT3r>TQvT&mnMUp< z11-EI`mb@Ki+s(ygA0nF6mcTN3bGQFhmW%~-2BwIFCOC~69ogfM)(~X%%eZ|BAJa- z6HQsS>&^Zd0Of}q6yRSN2C|U=X#^6l8BmI3%KB{@#u*GYX7!g?_}i5%n^pI7mB|~x zoF_(}_sN{5Zg=Z}K{nJB?gReyTK_jGQuJ}=3XK}0Mp&t+N*xLll{@i9azAd(0xQf4$J84nAg zH8^O0H~<4jl{cPgTag1#wxtmSw|YFzDDAE<*g8J|UhM zNp=O!w<(=p$rC3AbmRp>1G--4&eRwQo?fJzFq;4TihVQ9o;nNyXMEe=V>)_Tmqdio z%4z14i6#FgDS72-U2KfTK}1^@rIxaCL@>JQKE1RHs}-B0-G*dNH=MD@*ImmX|D!7P z^!7IXFLyQl9K*alct~8l2|M=TMg!VLOs54->fg7dgvMSm-8u!vDxyy6zPo=yz+~$u z%R%T=4Bz6$#xSP)D@@x|=RZ>hAY%qCKuFoTP0Ge=Y<9}W_t?Fht1C7Q%sG&NvwL@ayP0+|YN$wEr&tkTpt`FjDC?`Hf0QP3XgW`!CIp z1egO$t38BKvTHS!#MVUUb|hrmob!$QH0I&K%39Me2sGl}s0g>9 zJ?LAmc(aQQgV8xgC!fZs@VL;*QZPw3D|2!`QasL}h7C}63`QX}_A z)l!$y^j_fUmy}0G+{f(T5Y05zc%$xCog2Zt3u#Mlp5xFsa#Ut=<*P~h&LCKC(j9tx z!K3X6T#lK8;RmlRE5W$G_MC1rET7ux_*SgZ`d~?FF8Q;R+h>o(8(F0CF;5DkW7Z=vE4m@OtaSqehZYKZvZ@t< z6<*%VxVS3L3wjlyA$i3%6ogyA{R{k zNaE$r6K*V1&&bT1=+k;IkJrqrGlDqj9*MuT548!QtN`N-X%rL2S3Hm(0E7v3A>MuY zR}$SW*GbOZ_&{=T7@-ZprD%7!Br&j(pJ)R}pM|!7X~3@>p==7!eB3fnh$gN zF`37#$F96zH5i5gB)bw2nvY%M^0{^A*+xbxoeK*`)fpG(#;I+5Ft0VYw-`3#UY3k% z?bm+C#{zv7Q7oQZO4ZyvL3Ta|3cNA%od9mQK+;t9>N0~7?Fy18ZNb0_k$mw?!*X8dAFA0Z^93MK4HQ(cq?>$T{j^UQj35{%)faKGU{K$}Aql@7>$xDk(Y z?8A%MEo3Z1O8RNmyvd#)&;ITsyxyd>#@Lao@O-W z(7)@hK!2u>y@M>+Q`q%Bjgb*Fb`@D3SO3@L_oFNoisL&3c4VfNFVmtE#vMZI_A z(c0>klG*PadwnZGzk`6*)zTl!P;Z|JwWI+u-Y*Lb*7AjU%v%|Whl5_DM{e<1JExz1 zn6>&`xJ>^;xoV4dLkV2neSDsr^p(eVF zwEUq$FZP4zW9HXQ?-{RPSmoP=Ufp>eS!Cd55J3#k!t$XaT6yX9sH3Tlwz~T_cPrml zZr5uC*@B$8ibX4A^8*1Ve&P4J`d1XJGtns*=ZQ&FRranLiTdvqXnD>~Hb+A=vt4L{ zrNs=^p`I4o8)CBWyy}b$q-BK8N?c;G()9VNwt(c`n!eMBzEjtff(C~m^R!nVvBIxA z3Ne+!B|&TClZ-(4J?)jY={d z>?^8C#u0)2qQv6Fs_qEe1cBL!{z2$PSR}m}_skR}yllqR8Te(Bh6FRLvx|-%ZYf{+ z`+3_{hVEMuhgJMMU_=_qQ8CzVM<(uVKGB7s6G+TTw%opM|1rXT+9J^Qv3Op^5^3Fx zIXWnvrw_`M!<#lw0sruI62{^EDEL0>R+5u(8ZdkswImk+SbWyQLbl`%*M(1m*|Jd> zM+;))LMmI>(}ZlglSiL>z%UIzPfA%GlH_*>Yubq;M+BM3?ec#7>=pA@Fbnq{3yig{ z6V((E8Rw`bt54HrGAU}w$xN2QMTGT7uJ2vaZ;jznl1c!cb0)22h*z=AzBA`(%PK&` zE8oZo$>=M}af2BZCNM-2hJ~zOCMm$^%%g$~h@CjW>aA&sKbZ0f>}v%+xi(xBsQ=*x zgPj%Clt7BteDRzu#(vi14DVJHfy6k&3QE>GH3DuNw48Ia5bsT*0t-l?K8;cnu~#WP zA24TUS{O7kAr{||Z4z?;DfL@Sok6W2y)!+nskHwByN2(#q!hBb)CR=2R-&zVKhXt) zHu=-k4~E6v_w+U$SG)}d;r7ZU+ixJcf<^)*?<}q^7Z(Tky)hxWT3(w;9ch-A2qcHC zX{UW_m`+Qcw5#+635~G+iKmV0p*|b!nar_B3i^2Dqbla#Q|CxI;6Uv^CBH4oA&MfVe7e_*w3HK70t4F6YGs^RaDIuQDv57+{KpvHWs@wUekmA-V@uy zBM-4`1~6v*QGw^g4CCe#j~oY;t-xr2R$o}@$B2CK6lJgc(bIaIt%gxs5g@JJf6XW) zQ}$W3yyNX3k1i5VY^gQEUV2=Mqzd~%;t_jypHCjFxvNw@twui>ytRR9;x$=`nQqcg z2Q1M3Ukf^Fb~V4Vm#qVCB)`}WkY?oNd6^B8*3B{NP%g!)Hk0RIvx=?DAvWM7?*)#4 zmRGJa5v$snx>%XlTPaL6djiGpZX22m? z%zA=9HRy@N^~IAw&Kok-k!h|(ql`x>QmZN(=;lvknw^C%3 z9#ztd9;y&aCP?&nB!ucI1uhXWUGP{=J zyKJBXZamMkgs5)Zv=4u7EXp>El!yv;pG{2-Y!VuuY@0VF#QYA!faB5V<-!2lX=JM> zSHcE)xmGVrwlo@4c#{*-G4UT!44B4~l=}%0)_S5x)kTfe`LQ{@O;i7-`tXs;nf`!`9iQpBd-Nz16~lEr(i>!Om0yE)%~lfG*V{CHMO zxAW4$wxZ&N8EK?1Xr?=`BNnm@x8KvqUW>`POWYVrqY&3V;8WhS#I;{S%Y;T)#rtNo z)7l7yN$!1g@X}H`QZ2Y|^*96;Q076k7Zu726&HXU#}EhDD@Z*OsnTE@sWY$2>j0}) zJpFmOnwAy$a2g8eM!i0hnxPb#w~VV*9oE?&frO2IK!rGZniA3edNQriFo*oDRw#=7 zqQr1s1c6(}te=!rB|>i36j1Jv1i(Qc9 z%wfRb(n$(5I_EqKQq0|k`&ET$q~K>T+2d9*`Zn8>ZQhE=lXrV{_hQI(g2lkLo^vLZ zx?LPHK*f=F5->sr%$Ret1ixEl(;oC3C>nJ2brTko-p|X*hQUMfgIgwb6iXRBR9%)_ zHgSER5N3}Egekdg(@1QrZ$lL#I(!f8@-u(~wJi#UU$hOV(fJ>6c#*{t2U zG%xFU1^JJ^*t_-~?m-DBlFzH6oFz>DPSfNv2hZ}=JpRg2p<^|<$a1u%I1iVaXwCjn zv}}LA3AKk^;8g#mwYA*AN<+uTn~_lH4i7&s*nLmSKSmUpmt;n3e&D-Xut!wuQKPpL zc*rH!?}*6!*zNOFL7xKwPkEaf{GF%H0#uuwI7jdyS37b$;fp8m_We#j!v?tkhPPsN zq@IKAN%YLBT?fKD6{<)&#`w-lg zxnTE+6%U)yb(xKxR~WBWEk=B_v}k)EV0*t6Q9|9`0JbfC{^4{LPp_7Afi!KdYNXGl zb&4GJGquJobaLcMHI9-@z?nDWq#no%q3Qz)slAQFRR zeO-p)=;Ecf!SAoW`pPj8abm&$5wv44E^w5$eHO}s>+lyuHEzdk9$H`63rx|)Vth|_ zUVRM~7e63+Ezl_B@Gz;JVJHU1wkC$veZ|@DaJFW-P++FZu+hPKD4x5U3@oVbzK~(a8;$uN3p{psYPi;=sFAU& zI|R2a!7BmpRHc=M863n*$gxDRWeq-?Tsx&>?5c`g&Tqn5uoqD%05Rl1o1uGhMdPo1 zsID;R)A!_CemnNY>^BwU(J51M#k0N=kseVf--sgfcmUiQ{2&ZI+VH)ZEZ(C$+YsLlxm*iQ`?K23pza7%#U zGn4$Xc6^iKkcdIcjv>I`s?tEyx{M$E1bI5!noqZmAbvu}-PfaIgfA;ED`=!4OnQK& zXsxnyPmy2`%8jegK?09Y{8?D|(-8{NbM02|IemIEa}p-U=C)sCwPT{<#6tf~hWcE& zwqQ2Lp9y(wA#8h@g(O%?@?se&X}V4wRtMyPHfve~)KMUtuK3`+WIi>-eeAuJW+SN< z?1Qka6yw0GEVxAb0VJ=1U`S2cdEAQ&!i-f@Vh z)NjXI$(LwTP(&S`d-;a@R!-*R-aJ3;|2XJKcA7&T>p6To1=9Kt^1A&-TD?vov#unQ z0F?jWJJbiobpibgiI<`$JPU)+b0MdkM!_GYZ%hChMJ7)*%jz}VwZ!VGZrm4An z@cHEly!=AMjCAo+fF6^TE85MdbfZHzN&zYMo{K4p_~ zGawJ5doX7d0t|~c(N_@(fETx|_wBp$<+ZJ6Vr13?v$C<{t0KI`!$QR^$LcM5kc9kl z5_Zvnl{8JjfJSxzB(%mv^y4z=CdO{GgE*~OYQesU@;OaBYNM0=t@S5z-z8QU2gU|M zyC1`KCX|~Jw9={bWT2#)dDMlQw zmVidd?yt&V$U%xc?e-Chb^`3NKt@&em+CVE113SrA>m5EkiOPrOaU~yg|c= z*La{&%ypfXE3Jazux_TRvv(#dqvqW;qydgw4K2Pi>@xU*j0X3SO7-c6JTfiGs-AQE zYTq|}FRmeE9feh%h`4O8-3hW<#_}|el#kN_!mQ$9FsR2sy7tj_Uk=}aDBWtD=&|2( z+|$!!Q3$@{zeWQQnVW0XMnkkz+@%ZkLfw`ehLLfDHp@P>1W26TgJ&y4Etjd7l0@UKDKZIJ?NCBm_!8GkP}Z5N^FTxih@EF1A%2)=yc*#HJ+I zUl{Z1VR`}0uNt}hLY>>?dh09sUA5$r%So`B4G@de6;d^ni#)<*sgw&?&Ew#Q&G$%K zE>@cxrpWb5gStc}n!6rS`a0-F%`BX(E?MVlsNv<$9R%@>h@cqD`(;$w%?}pkOt&?T z-{*i4AWQ{(e$5N`P&V%y^6mB6T5JyV{{d$cd*#7#^!2bvBVWz4ut*cd?EsxHqMwVoMhdR3F_y0uf05<|C*gT&KYiTZ>pa zsWFqN<>Rzhv*SCwAIdGH>>edG?T)NVWPQ!#&Y3~Ulo>MZJX}Ls4-M`HA?UbO|59wY8$J~u)b|_7Pb+IW2okFe&m9?iaN?*WL*0(#gT)B}Y~i!}CMJQqHTh|QAOL`unWuO#hn zpp;l5ZDY~;H+bXX#10p9=%hbnkWv1a1X0h>znwOl-*t8yEG8yyPmGU!{maAg)M^ab znV{Lv72_x3_yZl_Il9Z`nmt|l4(jZR8cM*uX<4!HVh?F+xT+Le&Y0nN7iMC+XUzFpcpELF5IN^_Dy zo)JWg-P(_tk!@`;51WUjLyAhAN5Nxm9L=+LkUk4G! za%L{}l>e&*!1B$xxWM5U`A7Z{dORag^(#_$|BTq}V6&%+X{5F+n>5?f<|3fR(qoz{ z`8Z8hanD^n;gz=*Qz5ZPyk$e{`j|Rf8vk8^tc2VdNRHkL#sMFf8$X3TmGz++vzx=` zJ&pb7-g1j=TEK4I2j=mDiJy0^Lk3#!PK(|jwV{ANM)Y&@7V7gLtyG=00V@l)@W#zM zs16Iu)pWjsk5Ua2nB2AEW$?Wp?7pep2ui;7RlOWMWBncoJ71cN!7d=&PUsvi z-^SDEdD!rmByhE>^YdBQj8J*L0isqYJPbpk2Wo`sIOw_oV{ z<@tDN5rT-Y1Y9vO!b+&^-V=i`z*Z|9AHfJ)HejocpE$F^fN7sge#X*T)uXdu6+a5| z4mr<8McYYQ(Gahx&Vj@&sn2_42Ab*?^@@386Z6vl)hI=pSI}v4t=#yd8$)^ z41@f8tz32TpRmDJ2#UeD5m%&Y9fYJ$A0`GW@rnAeXY}8Ib^BBWgis@4coIfi z@xRPQXJgm@V0H^i`>Qa@tcgAQNUV7vSvN-pj^s|mFc~MpFkdw7>@n|SxhC7g3jIj- z{q%+kSBu3XLMA;zv_C!Q)V{j7q;2bHV!%^oec-9RYek?=S@V?tBnRI;N2?LVZ~OM6%Q$d&RCJBHeqv~d4RIPN zzi5hg6k&vUVw$cJ?A7=jpPk8bfa1UZy=>vs5cD}ATxMLS%MCfyw1W+a@{XY2teR;X zsj6BOBu&PgLpM2E9(U{Sn$cN{{2|EBK}{1LE7z2A8tJJ;XY@$U_ej`HtA6;D9P;J& zkewkED&!Rn!3jatAI5m`mqg#0gsg{Yw%9Qit^phx_7;5AUfcOF&J)dW-~Gg*Y`My2 zQ1>osDnMjaY>pW6fk{+0drPJXB;&H)dsSg?Hrj={)_43v-r__xZRRn{X}R(5U|dKl zu1x>52sjC>*&kTCc(rmX7G&7ivq)9r zp2Q76%K}kb_5_cq#c#Ji;NR+&yYJ}VcfWu}V}7|+WqxoNJ5FMg|9!fBcd&vS0Sm&$ z`HzzBKJtRHI|MNkI)lULQHZ`7P;!&a5m=J=dPW3>%|*M;kWKw_pjBKeCa8@ftkIw- zN%0M*}6I|JbXuHktv)o@+=sAkm zdk`SejZD{s{o=)RVXD=?qfftd7YQ-exWGHTOOwM@{fxHeHXKiKCY_WGO=_9tga$WA zdAJ1=#xzKAv>zYxpY`BLsq=o`63<|&)Ay-B$pXtwLih&ulr$!yrADnyLA zKKJ*Ke7*PP${J~2*n_tPM$B7^De0TrjqC2GZKhoQQ8wNzGJFeVgK$bpXufK?%EqTN z15*x}nCwH2oc@&v`W&c6S>c%)ak1l?_&cnS7~1$y(VeOQe8olhP@C+DY*8Us?eGe0 zP>^ikk^9|m{Lv}H@^dz1c)_{?!)bLvfmsu_Nw788YMpY^NdGeTWvyZ zh4&;uoVz}AH)lqUUz&$>zoI6H&Lx_0M^Lw5i~cd<6cxl;TXBcd=TN>&I18=yY@?QJ z)$lu|cg>9nQTN+mv_YDagExUq=EU!GwG|($N>Ay~)dP{?&Ws})ri*vu)O(oKz_F^h z8^&=xMXg#0L+F_G7;bZkpv3p}YOx*(`~6l+#<>+t!P%04^*)OG1jF#Jw@xqv=G8Z` z0v4}}^6teNVKDNjBn;sfz9_(12^ht&tbU(QzvI<2UjW9Q@16;k^OFJR{j>oU8euI9 za4!MxCBr+oV23TG<1fkdhd;tFAqh@Ha}#?LO&)<|{CR(#i3er)_o3NVPAIFUdtgDU z3f1_nQD;wI_r*7Tc+c_bjK_4jdLZWH9fYfC0$!|m>p8xxHN?M8C%Mahkm77Y2sHcv zu9(uMBj`H~WaMU?1k`)%A>D^(%aHA7KzOqsjMQ^uFO-*mzJ;kdx+v5sSsicwPaJ6;6SaRfCaix+W*OK+*uN;*w#?k&LFFh2D)sg4E&nsnzSVKExDu6bWA=lor{4erd%}CffJX9veEvh>z%e z6(y7beF3zWIp8Kg1J(GN8#JE=YQ>J5spsTqOArt!tOfKt;wJ0Y6rQI>)r+%{`NH%i zvP7`!rVxtUB+>p!7e#W$3@{a%g5$XG4^zMdE~=$r5DBSD!_CFJYy4@uV4x&p7H5)8 z_Zq}OqC|q%jyB7oHh^fktmV1Toz&!Wrk2o*Zg{|uKfTpc)QSvMa=6jQvw%GKH@j_V z!L7YgLA*KoJ3;DS9?yf(IIm1J7`rogIPb6fis*^ZwD##G8TZa+N`6T8@3cJd`%eGl zGbXZLBqBh^b=STk!3270qW5pxC$JB79J22M`e2i+@hew~K-7$$7{gRuaWadfFQbnj ztRE>$;0~<{!aI)Ad_*3clb?cJEZACJ^nVfFlQgKO%#Gy|59o2*iJF6~_gD3gxXTje~Dwu!J(Ly8NBTGZlgONxy zO#~ZYu&c`t;Y9keAPygN2-nA*JQr=i^7`OiqF}FSz#^ZF8?mIXO3nkx#`hIXcTxix zGN01PbTfxOGOp*@kkVIo@sXGy*t7-&2l4_#h3HJ_MX>|1Xnem*hK^}KH{+Cw>VT^> zV7Tmo=vJAjiK_WW=!d4i^F^i3ozwxqt{OJqy`a0sPvt9SgN8Y$71ZS8ji#9&zGRsh z!A%V}HLX~)dZZwGY~q29GpDhp%zH_kt2znpSFD)Kwq5eW*IsHSv|pus)P zgPq+2fDN!AiV3O)EYt|($Uz-@nYSlK5HbjoD)D-JZlR1!2!~-@gZEj$rJFUtkE$0= z96Lx$CY;H3UnQ6HPvl=S$`zg%xO)Jymp;+D|4+qlzl{Wzz~18$4S8jl@dUSAU-zUi zaUU(ez1~WLogHQxq)V`9A3J+|)?&vznO@GrN9g+}Zh*u7+29G@tZwiC#_-M2lRkh2 z>Yq`~4n}Hl*z7$ut-#XAT#t$By2^t6TJPe+xG*}3P{>dRPKvmx*9fwRMY5DaO-8G! zB>oJN5u(9jCmFARxP+$&k^mL=1^wbp{te_YtC|$JBMOwcbjpW$GI0-%QjavW36iE9l&kL-VG` zKq!NV&dnI3a<~|R9snOxmwkqgjiAg`gkb3lW2J^Thc8BW`+$g0V<{ZP2Cfm(0ci9b z?+~DX_12jx$Hhh#%JJ6w<|u$M4kdBRJ zAA)zDlK3t+F5-{&Ub2G;2&J4p+ox3)+2LB{kH***GVs2J?dmPwXp??x)7%~A9=gPu zqCd|V5V10F>$sfU()jH4f{RLOKx1D|ib4+>5u^`6r~QwM&ClBYjH}OnhE}20xJ)o! zt`oR2#9D02)!ood#MA@!Pjucj2Z6wZ&71++w_*(X!Onc8x_zuN7r9geCR#qrsRlBk?dM2X7S7 z+xIgTuI*T9AMIFZQQ@gh4!W-WvHY_{vpA1FuciLkd!t-f0wC7X0^PY%OOzx;%beXc z)d^XBKJWUinOZSsMvDSzp1QP#a7z}fnc3ey2Cpu&E>Hv=I>X`7 zg*5VM?BDWBiBwwue7waCt1;_$Nfi@(#n7Tx^fTF8U5S=Hjq>~ZomQb@8Ta2<|ChyQ z*ZRHzW~0>{`2cVg^9hEq+EwQV$^PN(s43#9jNF5s23XvVKC*wSg?QH(nvQbke*AE& zqAO!&mOsK-`7yr_1v~6ho1G`x)cE~Z2^BN1bAj`=R0I3)%%1xo9`Orc@2N*z0^3-9 zj19Pjz@xv|?-%vrmir+3ID=OGR7W`z2jvyzHVfQD2C2%Hz<@ zT?M&~NV(vnoJ_ehBQ4M`@W0FommwT1EHwe_yS~MHq_cPUm2_o4`0T9_7*}nFWi1)0 zCkYZ)2$KVOxv%X5$Jj%Fk{R+ErEznm;Q-sFi<#GxVtuXwZy5uwDic+t zQ>$on-WUnrL*L*Gf+^{eZ`&jdL@Yn=b&Kn14fATAoHUgEEhBU~c)II1+;xR-+O=tp z+sLw;_%7yZOEsj>EpAKfKWk4-8cz`VGnw^KuCN0SMX-TS<$~D5o$pAWgI1NLE_l`g zK>L&CNl{reO2c%O>Z5{%Tb=1yfOR-;P%|H~tXt1>Qxa6zL9J81|44jh(@08a!z(AMH@THTu)#e`;lO260S z`_@RfQtPo-(q^mGycK8N7sdyY=^&HjW}I(2o-b?SB|!m(T}1i_k-T?>@8w=dC)GC3 z0HGq*I;8|zhw)Vfzjp0Bml;zUPdaD&4q}>fOldQ|5v0K^qwTfMTZ@Uyj{nEUMm-BR z;zXAfqKbeqI%4D;A{}%Ar2{L#%D($|r0xBmE=p6*KO4VW?L%E3A7FxnhuS6S2ySA= zpbeLJz~PsBn*Zr#8PzECj&KO`D{x##`9c*565J!&*$sPKayWgR(2x{S?I(yUI`zqS zWi7H{*W`0V0Slbt_9>+^T-fDmTBK)u%ZFv(I(H`GgcWko%$6wYIjPl)ub|#|uhoCQ zsgOiIzLVm-#cwc7P~zQB7Zcgu^+Qjy`61L|vWaZCXr7z%mGAVseES%A!~6jcQ+8T| z>GCr-k+`(>9*fgnBWH( zlY47LA9wdXkd=LO*q+=RXnINKVl4s~Dp{`D;~K-kr*90Ehr`o*2|f z;yQn4@SguFB9VWMMYYDuXWfAj415-@KixNPO4ILhK~hOv#J_m%}%+(9;kcl?pE zJbeNF8!2M~1erxca_Tvce&HgQHqF#TS}s;AgsyD7sf9z>?roZ0lHlG(ne@A;6bYaVKzJw^E1c+^&d$tmuV%9pzJ6cI z)|B#^sBcPxz8T%$$?3dhrh$9oPvg%cwHhvzIaOxEEf6maQ@-iHb?%TLg*IJGUk*K9 zU%(-7Mf`UrNqJO>;{F_ipGC!Yw{TIH^iJAto;V~(DJj^BC~xpUy4q*a0*sZ&WLO23 zzaAtk>->kuPPvr$w@=f$O5@M8=O5 zUo%#a98u3dvBPURo0>6D^?Z4Ul03i5=kgf91AgXINTOwI19kUU`qFk8WzLV^rS% z%=x>HJGFoD3%%Bw6j75CA?*0QEWLWt8KtBXBhC^>i<0ND`{E5zquC|uR-HW0AI2^= zQ*Ima=5R*Vm`!2-7aa$?;A_4gb~lxa3HdL*!p`c2JiK?V1B2BEXO~%-@AhE3^;;}| zBC<*roccsroc~m+t>CRXW#9VIa@n~2prbB00qOBPEb58D;+oc#@FO{l!WE|uh4mic z{d$iMf9nQ4j#L~#w+^Sid4m)t3SZ(GpreW9IQp<5o>Q6=K&9%$@uxpctYT3dpZ!^g zF^zGLYDeXQEFF8*po&%rK0NUQ%|3Oy-6G{YQyO0d3R&7I@KxppFyl!+?DXxRI)$<9 z+YO-N1JYny9-I~xteci{klY1P86Ef+?JbZI|P70!jN?1jvKGt5F?ei5L z{E|QGnikhWs~-EsbP+p3O-=+0jJO?+p3_{YtY#R~vw^&xl&4U!u2zXGhmA&J?$kr#p`w%{O*)w8NVu z{vDQ(8$Y4#c~M{2n)pzxskOhbM#n)Ske)i z5Vo0@*a;GBl)oTJMPgcFJG`QyTd7`aRRfhpiiSPTBbk?oOKIMz_ziQDT<7oM$UPJc z)SLv1ak;G_mg28eVM62z`pS1fy~_|y>d%EAFMn`LO8Kp|RsGayuS*>yJfYEQYGRR; ze?6N#ph=ImgL)rF7ek1JMc%V?k1!jVlgHv_zzM(QOCnO`uktI5=WPh@mhsC=*aI1l z|Kmfzvf&cRUU!m06!j()>NHH`pd63$?EgNqBK;G-b>N}5`;etPPT0M)Dv~SjR;djU zz8j48y-u1!r0&N%k;kG0)= zMcCW(=V&nG$TV7!5w+#;Wxci*fYRs>U&*bm9u0+!bx3huYtj$Tl5~WxnHt(0kiQ{2 zWaP^mm>JjTr`R7{uc>aXF_&rDLU6xmYHEJj^FF>05;imAt92B<^)(DO|6=&kw!60X zmF8H#xtH(k&I$45f$bRL(Mef#QI@l82Waj%HYq6`TLS(AsFRPSri&lS)!y|8mT1}@hoi{RQ?e@=36NL96PPiF$xk>Zr5pDT^q4+(ni{7Ij8duwwB>p8((-am*DJb zEUi!4We$l8`!A+b{@91P_fC95ss1B|hCe3}ydw3kX2b=V6*5+(^%@Gvm4#@5gs7;B z_zV#{zpC6Ea$c>YUW8V85Gom2I0$h~ce3d-I_7#0pQ$eXiAUj#qd~tHiHlwpfvj13 znb{d&Kl~0gxrRs4S!)d*K93?>59d5g^iHAQ&OVB2J##yfrSFH7qvxp(M*fik-sYZ0J+0*fxFpX^h)qWH%EwT+o`qbjDYS5IYB~Y}MPZ z7(95rqbVTXuNrIDn%}es9_-E(gXq#fJii<(5X)(p5;@%dA=S0HMRe@>T^PIJUA&Re z4%G+8C`Td_pV8j^X02sBW;W-3t5ySajW>J4nK$loHZ+vYsV$B?E7APtW4QFQ^nKj-@ ziG6opY%by_NYoK~9XmFzKS?bq%*lHbpl86rw|kdz!z$L7{HXF8&WA+tW|^0n&Z{hR zI~0c>eqhzEfQAJeEPC}MS=kEjt*?}AC|6bB*3L0K>OI(rvrbT5E_)_S z&T!bE*tIcWx=I_K&Cz2a%`CefWawyN;PjZ^2nUH|oVe3FmXz;A;pBlS9lHz|!a`(U z=F#%YSP}7$tzqf-%9wXIkJu5muWE-fGbFmvf_KvhA|dCwEMwj$S~QDsQ(S-wKZibj zuO#nOLOwx8wVvZ3J5=PCre9r!qqmO=*2AQtc2KVFDl#2JSCaGTgENI4|M}OG6U>H8 z)QI)n4?91oh)i~(W`B-~cZZWAwL}AfTf%$(LEFrboHq}5M}a0oL}%bJ=|_hSU&)RL z@Bh^Tuu%7x#T!=M8vSLZ9Nslqz(fyXfATRB9L;)k1UcENrRq;(9^kMXVmIF*#6PKQFn9cEh7>@kZP>Xjil4n_+OVkve?^{n|k zm?aukzSYe`FRNNO5MlM)sLNo8gZ}uWCYtI0q3W%pqW-?`VFLs~VnA9tC8fKE5-I7H zZbq6RMY_AYyGvS;9%1MX>FylzdHMdV?^?g--&r$vZk~J2KKtzJWD;8zwV*1G+~k*z zU-@~xwd97olt_M=yLLs!^T$W*%BuAnhj+iOiS8OZdeX}iZP02hHFXcYC1fRM7pUIO z5UblhOj0vzOZKPlyO5_=RORd!6QtJa+y!`7@riVRdbqi%M_`F0m6g`#mYWmEwrtsz zl>#=Z<+64c`tzd4pK!kCb5h=T8M)SNCyO9*VX3&HUIy9SMXn974Qk}kL+WPP&A+@1o*-M zlKBm5e96DR{l72C$y*Ym06&!&Q2gf-1Qa>^_qPXX3^^znTFh5pneo$4$)gW0_Wx-w z{E#ag_d*#Q1=#90IlD$hdaP_ou+3tV+SyPoX4ieiE(V|_prn+MCG`)(iZI6{4dM!e z2YcA#Tdmd`kWe;3tP;=?&=pg6IT{?V>jCB8XcyQjtjX~3fne}PZKe;)zi~+1A|qdX zd!{SRjIaCVod2#`6ySUxyc0Yn{%?BT0QwT%FAU5*;hT<#?;%3eR0Mi58(oj!uIM(P z%XirSYXePq)cYsog%=$kUa21IjKbWBl(XTWId2o31Q<(!)%b3NHdiLmYkk_}rG(Ed zG=W}O1WC3w3^{k-*aG-JCtynm{2g%rh#4I$lh@Hu^BxBEv7Tm4ja8veo7e@(6@6B) zGxIXG-uDdI(X&@|Y^gBi)%K!XKu6no{;HJ3XPp9=a9N7D<5Z$p&xd|f0ZObtQH{>; zHO^=e^J_(V2C%`x#&$0Udwqi+oqdK3DA+?L>+u{M9E`PE7OYCP^39s8$)-+Dl0Z#u ztMf*{1wPPl@3pM22!416Cqo{)-eyw1+tGzQ7HWNFN1vb^h>>P(r*0^X3k9ew#pOvof;DBK70V&b>ENC39+ zOZmRwqj{ENej&56o(H76r(9i&KkH{61|pZYc|w48#-pHx|(pg?kb;_EG_r zi073)U)yNeg)3vn=XTcdvrgGiMKBrh zkUs#!)2hPnOFupR%6>DIOD(rfa3nga>g&{eb6GutQQ2r>?AXd^Zm+DZZE(O>X#ziZ zJ}2x+adUAFBwG1b4g6!K|I$bR$3y=m**3iWI?9eR>$xpyHsWYOf!jMpYzj))!I@%3vWEw|hm&fE4pK!UBS^J;V4}-Y<5tZxtYz8DZ)?AG68hht%;p=5; z(X-#83~tNNwu3og>N|_27uWNP?TZOCfA?;`~Xuo&Q2I~mU_M1ncq`C z+`sHHuqgBfZ2&5*reA*l^RCPAajiu(*6pbSMF1b3qs2UUiBKmZB~3g=bdtyP`|g@J zZtJ`8c8Jgst_gh=0a)+%ku*S~pc6sgv!(u~!j%@hujkJ|k?Em6{*>=4w}kTd?$Je` z>Ny1Bq7HUe(sZkCq1Q*kXPlyUPL6xt#}E$^zUWX&t8X-dK+IId{-(}}!ch|K2 zLi&cmqEcLR_l+Dz*aq85UTcP_WlocNUAy)#z}&Y0MXWe&nPj9mdA;wo)&J(K>6`oG zMjK@5YWRDlV{{Aa1MXP7YFnBC{u(0w>8e>_!f^5@Kwk$EKetsVU6r&TVG({(1Ut?+ zt1Z>Pad13f!%ydasxhs8TffW^7EcGs>58+Ki7hdE^%!8To967B8H{8pWa909xj<9w z|1O+yoRW$>t15yu{?p+V+FFQ*vT^?rPO5EZU0I&Mmal@>_Fd1U|Mqg+S#P!cuBear zN45urJt;-{4CN2xUkY*;Z50xZr=#6FqX>rs^f@0DA8U;q2v+3#p&GS-bmc)E>nj- zG=H=;&0}hVZrs>&>J=?SL~uiTZ;pMg$lVStvGsYoCg(@ro?waG7;-i0F>TAqHh)3> zHx^YfBv^mQ45zhL=M0dlj}Au)?+F}Zj|k(540RR{=6fVI zXrdz`cp8~2NHW1wMy-Ftx4Wo(5rMvjm-lX7cg=%>$G*X~rs1C%l601jR;il@UOvq= z!_a*%16yIMLZ0iU^fd4O+nE^R6BOVt1rbVeXEHwXsPfarr!4QbWzFzg9YEkc>?bA^>@vwu#Q@I7N&Fq&8N zgA^j`x}z)iTOZV1TAH@4Wo#OXjf33q74ST)WG5B;EipemM0ZUYo-#MS&U5+B*9eOX;Akqkas$yO!~|IuYfK z?{t87TsLGOB8JZ6l^)NVqA^?}L=pK)%?+4H7dtyzOJ+KQt#tot{{b1P*PABC0`G=< z{oEh>pVC8PNl@+e@LKLYCS-83XYIA%7~{RR0^S zNY+k`1A5q5xR&DC6O6TF#rk{Hc5H3cW=R+kwjz4o#$va7qYtt9@u_}W;h!1+U}x7h z#uzF{fT7>iMqjKP+r}^0&Ub=n7(tOie@ely}utW zN*48!H-Y^>?R@_2iK!H%kqs+!bRw`FwI%tO{?9Zlwdwq1cW0_}r@+tT4Dk3*VW zWQfP7E3fmJj#!km7@vPBWy*qAA%Znc8Hv3lHtKBE%(k+w^`j?wv`?#Wj4bz8hW1OH zAS6jm98ZDsU>R+oEseGPk?beOjXMZe(ZVZ9byOnL8wB7J$1vI+p92mcNB-24dW3=* z&6rpOt?%EixY^8=$qw{3z=YT&gRArs&ic|4*gEPiKOYP@ghocmA2fM_uSlz!qT3(c zT=MsIC`B4Ihe*ml>lj*llKfDC?rlP~N18=zXr}_rTLXJ7t73lPM(A;o~Yyg#dNeZ1B%|O!B)Z39Ox_WNZCny>5rR zlAoz4vp!I@e%+jEYJNo`L;s>x&we~!5%s_H0V<{L{fXTKss0-+UaE89YG&Ep>&L>k zU01!9KtX1Q0E7&CoG=DQibmhowA(#zq0y0ofcT{iYvrb(2tGi*`+`deOg@Xx#g6k* zLZlZ@JM@Eyr z!hilPmk|isBN|BmuR7KzMe)BS3t3ISju`B5mU@;yU*X{5de*n)u?(Jzj3{ghaB;QG zF6i9-6~$%>@2QspYTsT+A4%rBqU7uax&vwot}q}MYmFm3 zI7-fHgFZ@sZ+Ycg)aD(gv@#&jU>(gMB10k3ZEU!t%o)If;fqC|UT<--fa}ffLO3WF zB7gw&?b>2}y2bVBxbgkVocoZh(buu?L5 zRnpMEHx~xfeG99<<{aW*FJZRmX-LbsjRX(z8FD0uIW2GVomd1Nn#Miqi%n(z1UPkU zVFUeA8@s^&g0qVNFooY2LV(QmdV4t)6fdVYKw#!#r7GPw-j}BWKd+$aTt^W&7culu zN6UV!^mBI$<6Yq>B|hw1H2T9!wz((`+kXZ5qC=S-_|4w;!RY0-d{8)`sUwO{mBp3? zP+WJ71hYS&_p^f#+;6D=6%6D03}ymBFAuVcHAS0Bj8_u}9u}Tu#5pF1ugg@39k%CP z+k6*8i^6-KGtF1qc}Zb?xJ$232d@}sfB5-fwUYAGSE64TnHOgs*R1ak&`T(q?3BUB z3s7zyW(Du<<$z^ci1BoTzVPs3q^=Jx{&Y!1;YZCkL}J?ad5fDUd(YC;4G}0>EvjCF zMKNEcPx2}xQlYWqX!Z1papmNt1+QCB$>Pr)*W2u1i~_p=?>DV>$PG924=5$lZU}cE zzP)&^mJ|D=$E<;ldy^TdjQQcH*sKd@CnuFZ4f1UsKFgWa)^^Qpd{MMdG& zx6{8HN*54w_>0A73O5gciay#48=9ux^+$nX&IUP1=Doak+U`3*@bCVf-seRyn%O7nMbEFF zT@OikwMS2+Y}SGl?q`MVvON)v)fl}lOx4Yrr?#46HpCz4nc12k!bGMz{M8cn7E!$9 z%6qSOax(>AJb$nUA;dw@&tRR`o|#wmK%^S*hMm6)g1z4AMxGKg7TN%su%tjrw}HlE z*qI<*YI%wnD*GUMbANoNs6*!i-GKOu?O%)AcJdv27h>xfV;(@`=k!XMBCBv_i1YTz2`0{1 zO@+|A@ZKY~WLQOOd=cVj?t`N(*TgjP-A*~gHXWVxu8((K*TGqBC>Tq|o3Dp{_Zk)d z3@`RYc;Bt{h*~ztEO@UT%0$-=S{e9epH9jlH4<^LY`gMe{C$m31vA^w#^gy8)9MY8 zZgVBkyy3`b*Ej4jmp<0{cY=Un7+n@`K;@_*FLI{~u%+j@|L7#7o!O*vR!KUqhdLJV zN>WRZqAENvQw7gf6R963bRfD=9YAP;cv@ccN3KVwWaeoG1$uzoUPjixsLTLN&pI$V zX_pq2(d|&9ku#el#}=W42}i(9Au_*;f~`ez4_buB4bgm3r4;Ms&t_3mcn>xccqD&R z3nO@%zRy@-Mss%MPz6QSeESPhdS%VM|4=^EBzd}}OLfZA^ELY(F3#0q?Ck7C5mih? zk=2$!*L_j5>{J^S<%Jq*58w(!t$b~*FXmB(1EYDgf;ztd2k})-s~%%QWJ=SR5o3+( zPjq39q@>su7?pd@ybg1&68NKrIZ*h^s+sUdmh)-q4eRec|0W_j(2~^Yr`z9%SAny^ z4@x(|VI@cxBlof!m*J53h5796DTS!Wr~wqrLmL|`-`W})IJ`N|QWllS9Mb})=nRnC z43{>lugc+js=0xZ%Tf;4Q73q7r2B9)4qZm;#BFc83))Et(D zcm*meMi-f0og~zLWv~=sPK4F8sLu)MeOZ{zA`O;dY;X86H&y=Jq4n!|YiJM&%~v5l z*0626K~4-sv<~O!Hw&S>Z%2Ll&f7?Yn#|B-nDKx2W3mNF&zNy6J;(zRCBlE@(bN0R z-y!AcAhRoSfXUBt_J7cZG!a@r#I`>h+z z_g(eO#KL*`TIhr9T3uALE46=XxDpctK@|l7QC(OOxqNY=d1SdHnKQ>`Ap}W0kr=jX zvm0AL6X!r(QHw#^W9)Bs=wW0)h-p$;n3Gu zd3BBy@^2BCq|5n|pa%JZRotKeT$PR5H$Bzp0$hC9b$hye*k&ll909DIdB$%jNzu7b ztP5LALycwyYM7~x@T=PLCn(BPQwyLmI!R8wSq69^GbA(BguYxzc5EU2>l^|iMpyEu z?VKm*wUK3`(b+;S9+ndC8FKdjVvnSN-E*rd{Q)pIMznMHHIWwk6S#7?HCm->8< zl@eo6Ys3wbpedHYF^~D^TK`SdN4I*_0uNR~C;7z$s+Mso%m`C$lRH{4~Ns4NW=U>@#H=I7mH@I0elD02218(29A|_6`F8 zcnNQ;3|9_{p1L)2b=k*pOZQKhNAPmwG(tbbmVBbkSmZWtAGz_do++6)xAiZ(-14Ym zG$DSe^TDz(f9&r<0Bj$KBd({rL9c|y3+uMyS@FXAs5510XfjXlj|T1)b-IbKu$T#= z=?j=?wGH)`>a0zj((Blp=@4FuSL6b%9m@^Y%3A4H)C5zy!bu^^VzmU2ucI8Yi9|VGhv891@gR?0+DH9az8z7)Tv+%l>r0wH` zkap}fl4F8=6I@--ATjBWeS1T3&>RF-tyB4<=6WtGp4roCe%;e3d%YJ&CeL^1%#n6| zWMt!Nn%LZ{XvCVPUyStB6e6@ybQj?TfXvn_uhnc&PVV#aR7{sHK4|g(%U=c%ig-fj zW;ylV6Cw0|g=~+7MufIYHWDRT3DKEz(4pvfkCl8Xmg&IaTMfqVn!~=rWRCV@CVFz= zBAZVg7ffX{IF5eekLX44tEyufF9={RJEkLu{Hp+((9Ww7#wz0ROAiZrLgBtXU9(@<)lQTyc4Fqgzi3r3 zuAQYm+uMhb|3i_nQMMtr188(;isql*E$y8Z5fy#!!3fcF&)`1SzL)dw^H90s$TxyN z!yd98BqUNwJzOpSen~th>`KM<2SWo{;Eh@WMA)YqdO6+;AuJENiN|EqzX<~Fz7${q zAS3z!+cq@dAXWH-WibwaCttg04BzwE`$@nn7d;B^M)xb@bU$01z4!dfFvC_jN2A4``!|%sXig?EPhM8270lSboHW^BfaImUkMtB2 zejpAAA7ScSm|s^M%(?x%$qxpte0S)oMz*C0fTJ+=b)t$qC$A3i8ui#!c`|y*Hqm8e zth4fSl~*Ax=qKRC`o35;>q1*$j=sT9+Kt&fmfU;TYThiyUxb zJU_<`V&(tj$mv%EGL^L{Y(rDM3UivwBxB)QB5yu|R$vF}QA`-VFmw`Kc30Q@+@5wh z|B{dS#&#C63t~B(So76uy#BE%i|D&` zgI(><$ZnL_x>e0&k{7jy;U|XW^#>;Yd%;D4`IwuIL{HeA2W+QMlZBF#fc6JFwl~Wv zxDv8=?R81X?(K06etwMZ8$4&9852JF=kPq6H`sM~;&(5sCqZ6!(vT0n$!{C`iaJ)I zETnmJu$d^%pU^7yVWHDfi}N6*tsK%p36nRt9dB%2{s1#LEuXSsl4m(6z5W^YS2L0= zMJY8M8!j@@`R!h)ec0OO#Cs&Ny;FSo_}KG#KgVBxDLpyL=)0Mm(swqZRaIGu>z(44 z5`flipU-+$Sg-L9YP?1#;0khG+wO9eMBAN@o;Mm4v=Y|E*e6EKB4j9v8>FD8$VmMVB1yP8ypFi>&Rzp5LQ? zNm@2MyW#nm*T%G9WKGat#c21d?9;&-rM=Wk42pDom#c2ACYYmgbl&1w{7e(MVxUW+Id}+>=c`NK} zEfG)ky>#Im%zgwG$z%}d?8Tv~4wa@t>ES*g0c5Ff-;A}_DeK!wUuxgKk|0qlO@>rK zq_+Jw(@Bcvm)O1vRnf%RpO(&`G?U@J%X@*MZt!<(c_aDM zamCb0uG978-lDg~0FfAI+Q4G19w>|>6nw=v6q2F38eW}N=J%YTF+WgrjRbl zH)K8Zba*3wqGr@`YVAVKYovcGTF$(}iJ0~8BEf%~u2;1a$?q1kRN`&GbSu6pTry>$ zYDJd*fy&LbYX%9`rfik9`)9#+!WqRRX;6zA9b*A{#f<-yP8beKr)bC}aj8teST(xcF z(@ON~7_tp>!6)Jy?!}D4?xw@+GiF!I$^HwL08YnNvSBNwlCb+MjkP6L<|)4kj?tXb z(n)>h7#}LSG-Heg%03D)h`aHnD1_GKMr=buO`;*skwjgDs|nqYTq=O9Y*+m6T~Z7U zXhwvx$sy}1@&%o!$mN+=fBy`IvVIVS^u=PHC~6^~y2*1TV0}(lPe*bUOMWffYy^~Z z{fY)EgNuwRGO{U74=LGv*8o!`y7b3N;8n5E7Vn5KjxkH>m2h7)hHMW>)$eUdgY>Iv zH_pL#N;7gBgnU>xQMjWgY;Lp9e#o8*>3RJf_2K84U-r!-_r8qG^jsZ?dSz1hWY5pk zT(}l@Il=Y8wN3AesRW&*@9rQ}>Uf2~YXm!qk%5~;#|!qd2uEVJEa#O?c)EEQCEdGj z&j@L$O4s~VY%&`)XZDsFJcp(7`(5K&=EC9bq#R6YOa13c9bT$Qx;35`#KRu03e>j9 zpXev8ubzE%8=%a&MWm2QYGQT0xOX3*!iJO12|cX4k3j72e;mJW8e3%^hkznYgn>v< z%6Bg>+#K1t!$t|c|Jg~1p_Dxuc&695mIb2NqGx_iL1`*;(pJrq()aTR+Hwk^C|3_v z9G|WHivV^cHlH3RVwd8aGc<9VaEsFk;mMa608&tL$_aKFagVVP?w>7&K_aXnDIF5p zKRTPZJ=#f?p?!~_)EF1k!dS32JdAp3#YJM!rU##2;1zKOPDv7) zNoPm*X7-~aZmg}{D*1Y_#I(2dGodl~P3P%{G=*_Xu4T_JUvP6Z&3rzcXZk0=%&2qx zo1y{I$tMks>&ta_K>t_sz8QFf;-X3=zAAUhNQ*J1#E5asM`|u)#Z&^PG@w8xPFhQ1 zu{+5RRYX%ezY(SzuRG>cPq)v4x}c&Szn0 zjG`WRx1$NUx^iO!kcn-f<)I9jN#<2ZB%&hfwD?31cH!Um^izTMIr3oVVE@&^gze|x z34PP3^Z&xnT+Kg@c4cHCvwl+pVJ5(558jB#Fa%Z0jDCNyx>A)*9P1^X`*?$}k-RL= zg^q~-wQBMn#-4Ql;vR>gxXb@4V&)M_1QbQvi>iR+<$T7pVTbA)82mMzgxnvU}G2vCvpO)dw^ z{tpDey3$%>@YB2&4ldsCo2z9>2lrJ=FQ~p;MG2DCfOD1ou2E&s(yYY(wO6V5o_Qne zb5dPIL?LZ#$lzM!W#!CRhUEgQp2VzrtOok)>Bbq&JDCqeNZ;LT^BS$+uicKKT0ul- z)n5BNlsla@_72BXzM%^#nUEDgo_?d2@!T;dyf9C@uZr(?x8GZ=H_AY;pza~&UgzH@ zm@Ku9F#jz0qGVGd5Hf-P=3N`x202FiMNIaevB_ugCBL}ER82_jFB{ba-{>u`H&u$= zO>IU49>HkQGsAb;C&Ij=olRhECU&XLHYv65mCKw|m>f4DSj zaj=`xB8Z7#Ka!cpbIfw@J2&x3#9veGhxW%iP*a?WO=)?pe8v967XTNq@EVh%_E7&z z742buJex!)BSm~CA00IFtwtp2w}{G8Q~4Cy{fzt46cQ@PZtafwsjfEfh8KIb>ATt2 zKiE%KkEa>K|A;;tnj|vam*IaW#gSuOxo23j%Oz791wVr;p`yo5DLKl94&7HMHm|Ba!KGf zp-0T~ynoku`9fXK?peT%ntb4`uL^Xzj4*jf`iHT1quv+jO$FtMQR*n4;CTuW`-^w# zHX-U8O8K=l2Ipj8PO{c4eY5EcOrhWziZlPeE{ham3^r5mwyTCiEhW@yFcv?|s@r5l zE1LB1vohNaiQaanzq}KCbt)u6BoYJXb|o1kPP={s66WsEjav3`8+NUE19mT+>^eQb zH?(t;@+~tsq0+a_zh%Z0zi}tQ4-O`c^qjCmyDiz#hE=l1~Aw(+t08ZWgem3kCIn?j%qG1{&1+&ZRRu&kgbkxix z)uZD`X#MlWaWPkufxl=XuEC0#x7LKdQ?`j_q4f~bp$qrC*sJbvXoi7m>wQ$$7xC8LXq3A z8CGC5B#d^MijlpVCPhEOY}K=RZ=VX6G`QDEP(1AhS6QkQS*>)sLq(`YXh~^U-4-a9 zeiQ7Qu#GHSKfq(h${;CgG2OMtX4Mfc!!c`O3(A|_a}c)ojLsp({oDqzW*^^rI%U0$ zwMJPRId0(9$U(?ZuAK$K2H{b-FkzbvbbU;@vF%1zg3!Vv?;Mc6!T4`|+kKkZwTwIR z&tG;j1UEA75~aT1-=n)#T;1YG4Cqi}i20m3!CS_dco!4H<70O^Uayw7bnVqq###;9 zMG;pXWDw-6{moU;P3%jv9t-g@4KKf*im~Ks&)xiUN4mXefju~q z^1U0{)M%&|&kf|FxVO3^iLS5MvYlpVMYX~%b&{49Y1AdamC_cQzKAv#6V=J3nq10| zBGB_Pso=dy$}afAUv6nBe<~eXH|@NBMrSDsrSA9CL)ARf?(?R-(vh1F_*!#vXu(Ae zvXfr&){+-psK%+9(~=_ck24ao2z{g$1(ndWUq6#Zq+w5c_dh)Q36fhi)zER?QZz>xL{|gC7mN=~lql^3|!YV;u%>OAl%1Nts?|WRzl-&j%quxg^|be!dMM zI!v}wIR#`BXl<*uSuZRzG^oidu@lJ|QtAaTcNKl;_22m_*#;SnlUysk(b zV*MW5YnJPi1D*Oh+4ka{KgA7Fh4v$=L~GH!3Sbu;`P@wAANJXVk4Jv|Y-|`ouXz=( zNQoF*Yo`>QSEl8Po~f)!l&#+o3CEspH$K%%60!(KwFdR`_HDP3TNh{t984eDRe5`+ z+t^$E;WmuzvWsfC(URX5lL~w6aa8K5L3P)b3H>7D>UmN=ZO$CW$r2dc>J!_$1f0o7 z)oo4MGiJolg6qLhp^hxr-Q0t*E=}HXJZ2J|9MpvK-rm|iG>I0IIBkWQN?VVsXI^o+ z9ty{)#2@oMFDhEFb!PKMl;?3_BD_+s7VC@iF#}koPpa7+R7ToqHfZ{}+202jFgWuA zQ>4?D=FN2Gt&uD7^T(ln_}hfMQuODM@3v?S$tsR$o)8AB zL_UkHJJtG={2s6BZZ;4IhT;&rzCy<$4)(y-guA^>7^ngJ&~i%zG;Gj8tRayB4fi1o z9Z+w9T<5fAE*8=N2n)@nZK$g~kK><#O4wAbYy%zMGe%=t`n(w; zKOue}mSikIBc-D9hug|y+@cWm%Do3`EAuYtS!ejwhQq8tWpEtVowdf!+W^b${3< z(uMpZg^!X+LCYlYLXN}$j?Z1G{1H|*kqfyGEc3`E@|^S*JUJ4;x`#>Va)|z&0Yh?} z3TzrqnD`dU&Jkx*X(dAmJ}O&%&q}46H>TTc7tvGqhiy$8d^_7K#~Zn5YIjD3NknXh zKh|MnQlH+*&UyUmyKH?s8|bhk1$&>~SUZW5%J4A>p4rMz!v9@XAVh0l*vF___`-L( zNZ4&7@AQvqOBd}FRcU-qZ*$K1Hm;vAKR?-~(2DDJ=YX)u+I&izaS;f_0{RMCs}lmv zVPL#g(2{1`&YPL(tNNj9-{!=hu1}R~dvM6qaFU2WiWwMQxQ7`!FS6F5@!2VfW02k* z_mZf+%-c^?IWkh!Yp*aq3w6~94=%0jcAKXa@S_0o7H2+|sej$KWqcnX{O#kMhWTu- zQy=vkq&YsVJRY*XecJfoEa(bxP~|mWoGnE5-Aalaj{SlkTPZS16(L0t{w*=#HK-P+ zGzmI&s~FG#j<ybrB!Ah4@(-Ew|)2e}R7vIE}VhXI%7t z5<68f$?5fkH3>vqk9XsEF!WSb&(LEP%FFKK!V>m6IcN$-&5CT?!ctBRW^i@6rt4VJ zw#Ef9A17SD6&@tYrxHUFjj5^NL=I!|Y(MgkYgK6+AxYBtxQg8$5wXE`cN}QMM;w&v z4bJ&4;2IE5lXXgzFOGe$#>MD$x_0!@{v~C=Br&G; zsD7rF3}1WYU&$)7{ZOlUrhHmIx)sl*Ju!l5oAMw~Nw|48c z8~1Rdlos$h=*dWE{#4~Bmq)TGW$BiuF|0MrOkOdZ9)$`aj z0(culnA`A%9tL{O{3QP|xBxovGy<-n6*f5->XkxF__W!lZXvd}Ow_smB4_4{DMCtV z3YpYCiLsez_r@f2vM0fVMwrMF{L6~F?_8uxr`|@z-E~n{N|GhML;e0Y#+mG**pJs) z2gw~9X<;eTvnO+X3Qre!>8#W!t5sn0w##c|siU#?VXNG=Me|^mP%1-eRx$URG8G)h zFKXUI(lUH_sS!3qEzWY~jw6=@&Er`fPx3Uk7pW6&!p2LoY-Bd+86<6JbW|>k#pS_@Y7&p(yNgvm-rbWknvSwPq zSLf!Id7%}Cfv3$TcO1ebWNWL#%#@~!pSK)$RjYU!j#zX0GDI&Y)-3MBLd5=TnE-4d5WI1T)V;bos!uU^A4|rEOEVqBlg!PRMzA9 z--9!j{)vo0CG!sqzz`k%NBBdsn}u8LChuz+b2U=e4c<^4iZT zoZ!dBYex3ws7Cb;WxWe|mLvgw|8|m&;UjK9^#<_4NfOj7(@d9}8_aUZ?E35jzk^)| zS$C&cMZ+kQnyeNM_F`w|(nqNr+NJw6)7#a#q{cuXf&S2o)3 zQPFSG4$3Y+SF|fmIQqs+X61WCQ>)XQX$PFWiUm{VYtzVg7p?K-H2J$cwrys-kZr6< zHS+PjxEa>o@h3cdhebF>WJYh(6)m-Oo_TTg`m-stXdc-*L6+*L?AS{QsKRI+nUQ_c z#wkmQ;;L<(GMjBzunPg1BXQ8|XD@~;C(d+T{QDgLpG!a356#W#^3B4vl6NlV2Cc3U zPU}aw)cLHQ{9Q|FV8{OKd+P(wxS|ij+;}9J!@*!*vlfo0;kiKgOw%lz0bja&Zb-OC zIbjmR@#Wy@_iTC?o_JNuSluUtAyN&va?{&kr6!wpV(518uULS?2$n#{N+xuxRJI^o zSH|`;!DoHZ;dzH5f0rp)XK|N%6r1WH%O$uvmx_2HLeI1n^!NJcMm25P&y4R~&v@iXCW zINCW&c>f<$qoD5odLo={X34YZM;oiY+Z|8ikA2?q4LgXW z%D0^|bu&$!LuM`tOIsMS5x7bQ&hQAOwlC(>-e)a=&M!hw>=hI?$KQcBiU9Equxai0 z1}$*HyqWcUU_0Hg3SGO98B`ys{2a+Cfw9ibH^Ic~Tvw?#%r}x@;Q~XhK8C>|15(eW z77OhP{rH8M%Y5|ohj6opr2H-m)xK~IFTcT9+jUit_Bl*c}txU-V0}9k+W5)6HyTl|sO)W42 zHgGje!0ML?MqS$2zN1reJd(52&fd}GLpsZTcR#dcGT>X%3sGmZ2)rSko8k~YY2eXf zxzie`kOO_NexH^z#Zk+{`ACbVng_7!1Kz?Ph3K;rUub#!={hve{$m=u)2A8d@W3xZ`~wtxtc zncPeW6>J;6l{dCFPO0J=`3>fH*fg-c9G2Htv}Nvg^`{x%yD8*Y*A-suA*&Po7Bx%M zlkWO4D|xZ8C)WQ@u}Vl5!!KE6@>H1O1ZxF%reu$HUSFNJ#%#0QJPrn-srTT^JhlJh0yG`BbBA%sfVP65cY>gG zSHnR^hOFclrzFU?t*xFYAKz#BpOA&@F3!aF_pWcCxl(>&d~KMF?6;|mE93s%-PJuJ zh7YIPtHqxJ^+l=(a&1QUeWsRlg5cXAqmi|dhhN9-%S-2HiL*2Sp}jmpfmasiCzX~R zTG04>YYglF-u5!q)Tk-IoQlf0GUmZmqN={(Pm{uD@IjN^{JTQUfm_*0-DLu!ySTQa zkxfz9eydPw{}vl;pJ!MyiGG)Qt$3i zK}vf9MH5w7hV^aYfRdPAu^`gDL1K#1B$Kq_H21;;m)kmODc(dlqJ7d z!(zKBJ2aHwj-vqKt#4B=&5+Ius8qb2tb6rW1?vqNAbtBY`d_bXLAZT2-fig3Y)@2f zUp?FIvh3vEe?}m7S_l?X_YiX3S<4ud|t6}aAn^^bUfcH+|i(8eU7 zIob-l;OMb7PRi2ahv+9?1g5`Y^x4j$ov^teirsI8egcY(8v~95#@^KKQaD%seY;9; zMcQN}i?dFbX9GaUrdPKc;E`d8yd{Uq#!YTSJHy(-C}F4u=+9NX8F3_o4ZV1HMb}%= zzD-S7tDcOF{gPrRA?&C4t7optl;<-1BiN@-I~ojkBP)ujM~n4v@ILk3$MAP%BwUb1 zHXS{gjEc#!EIuDDf7u#4XU7lGN=|w?s_pTDVKoK1@7dE6IzcnfYt6N1K$h|5lnTm8 zYTi_|`6x-wzvc4T@cPK)F|iRs6QMPtd{@PpOh$?T>#M*EtQ8hA@ivIhHZAb&gcP)k zePZ{1ngDpg5d2*$>i0a{YT4m)Scq5FhO#_+-WG58$z;MC3q48jqRe-pHw03{=Lqre zXICV(w*EiOK~T-6=^A6q`14gQ{3IPxVyVM6!+i`!Fh8( z-}U{-&m?E>J!fXknl-Z%36GmYUD-_4+;6h(X?vNT)l}5?AUIh*Nm6wmdYkh9wz*8t z>tY3{nca&9s#7>oJf5jDLE8h@P=W|kkw@Q;#`v7 z*I0tp%|*e%+duyo2&m2J<2JJ8q5)TQy{d3)2NnAZ`aGELBlb+Q%2T;8N+D7Q^U@~S~yhchA@LIkX8_GV@6DMZ0E)Nxy!Q=6Kj%1ICN2oU_@Fx zF*w)=&u)Jwh}KK|^uovsKRpejxWfL2d}wdjF66WPy-k0A&fm7Cv^L1X_uGF9IiIBv z?Bmd-9eJ7ADxhtIZ+&RIyAB%*jh@=n_1h51u#EAo z5%+Bk8(-W;MswVHzOenk32SEdN6S-fLq%RG>6cQW1U;C=e+e-+t>?0vJfq?dRCn`z99Vswxq#B>77UDeD=NmX2~Qgp@x-t znLQncT$YU2`@CM6e~WS~8PV5ecXfAlJB!@MuC%?LQ*wD{b7FlFIFl{5*38M1CVmJX&yJ#F*+;AHP6YZ@F=D=?17UXlG^7dB`!#E8wtUX?!jZko-c<^L>0G z_pBirR3h<5j#C{}sxSfgK<}?c-h&^RC}760{9VoZPmMK(J{_tIWvgW-Pkpyi5{20J zfjUMxxbk-9)nd1~nR*kjFo!IXndLYtoRMy%*y`E$^3NgTG<4K))H@O2;oJf%Rm_GY z+OCNy?0&I}!MiY1;c%)fMs+LLhUe`FaCSs1*W^T^dQLNJ!f}Z9)uB1k&cCVXB+~6& z72nW7MhnplSEcKqN)7W#1pL^2&x;`^suwi?To;ssmH@B4;>tkF3BwWRLrC?@6^719 z6-kR9wkI>~lglCNBA%LBI?cu7e7~GE{%VFh#R7^y%jkqg2&{4~q8X^=RqaA&ZEQCT zKEC{h!p}G=dZz4(n@6B=ggnJf7-F*9zK=!{vv^RkXC)|uYA0Q8*L3sTd9Bt%SruzU zJ&Q2g#)LV$cpY=K=}ddpYFe~=On|GGY3@-6#fdLuK2eTEfW)hl&pPy55@Ow+6nA%} z;)Yz;DVDXdySp+-7ZKcR&TA=)m4!9o$INyu0Mm2qLWT*6%Bnoym?S?vrB^uhg*{Q> zRwQ(?!x32t-s6*-(I4!zwmkBtL-g0{=Un_!h2SjJni(r9YN#2leX3T6yqIbIk|Lr2 zm@?G$IG4yq^;-)Gt%JWqO90+g3_DA+8LGQfr7*04I~G)xen3Sa(o~54-WN8HV*B#m z^28oF6uFArV5D;WL$7CoI$Svjni%z}uhFU1n^)Eq@bB5j(a@|pP;5G4ELBQojmNRi z8mREsD>P1SHk!#XhiD~vZCIp{^KQkl+ijnwO8<%&#=83Z!`)8Vg-CwbhlHQcIvZK-j#+ZvxbUen8 z3u6UAIc(6(Pkm!*ULPIg9qPfV*3!~+>z8BGJyu|_e!?-Sv!#%og3OMJ^j@8orY6PJ z%KRE5cj}tQ7b`UX;6thY;_|v?Ez7m#qzGj0uUu_|2h>YhE5HesRaSmB42jC$8vL5p z4i2HR2(um4WT8nk&$K9Daspnbv1KnQ{3@nB(3nT3dcC-LsM1Mr<6-enPJ^?9i;9!S zmzs*ku?nASRnda{oC4#}W+4n5WyRXc09)O&dDQ2}K2uTa?8zpIg@UwoG5SIG3(zti z2HQQJ-_LWYq25E^cx}^~_6XqA%q~`eOG&&GiS9cLex*_V$KRK)lSHm}=2py54jDB~ zi_i_&R4?Mm+=W%&;Go4^Ywc~0P^yuXiNF*o2}POc;_)c%kG&LZu&oA6{i1~tWD@Fv z+a34cpjgyaa8IlXf>>W*w3a?(N6~0H-QGm28R>{lM@(3AvF*gWB}`_(r&Rd`YJtDW z4S1QKG?4NPns7}}YFo!~wK|-{s2j1%K%6_;l!@5wSWLnFzFVRe@1KK}zx|xsm_E@F zc@~-&lThJS18EU+biH4dSrI`Wnyk*DE`pGJctu(M*@`Jo-rz@ugtabi)neDi2{T1vH#XM+Ratz{DRV{h-)fj_5k~I2j6@nc>2Wk`w(E~veET9S z3~sdkr-TFT$1Y_gFYhm6qL&rNm&(lmn-{Om$EpMxXMC&Zx0mVHL_Cx&68)1ngWOI_ znpcM?WR5R85pkGCPo4l}@w>A~J%g4;eDUXsBzz5t=`a&KkCmGpjaXGq`aQeA8P7my z4RyL)0#_19_Q?^Jh9z1;xIgiNTifsjY%|~zOwmtMn|c#|o0kC{qHDR{-0!TgsY zN&Ok5M#m^a7&jLoeImPE9GX$;+vQOF=p`Y+2(rho70l`JSFGu5rNrshcG6BPfbN(Nni^hspy)xrWs5MKCIp6j~hWn(u*Ej+9>}I85eE9#f!st zF!<$vQj)UGKt&$5q>4OXu8OtA|BXEh$Mp~X8D`L~%(9<1TWuo|R2uPP!#bDs+kkBd z)|7Sbx=YAaV$wT5v{=mLmLkMDw`n`+<@uf4|G#frz~+^m)DXy1U6+PQ=^&b7BFlmv z`v5Z+$v-xZ?@+EXdOT+G@i1{^nWy@YbmyR|kVrc0Bff^3_OiR`QtQF*cM_>X&}vM~ zHIzP4VBy|3#8Z&rgqpASxP=6%m8^v~1^6aeLPXeqjeNrJ34OAqiXYtn{rz>ag@1c6 z*6DLl*fj@YNED|EPbc}h{`%0H?ebZRRUtAmbgCMXR>=EGgYZ4xIj$IT%*K28=Lx0? zJ4FqXFP2A1>$HW)BTEzCW+mBaqDU$nJDqgC;p9pp?qqO;fU;x9ZkfSr9j=ernGV8- z5@~gS4PipKo@XOvTp8U2V-0KYJ&k%bdGddI@cRp#Xxzl<24AZS4nF4E(!zQ=eT}%m zItAzaj&6*!9RRK`6qn`0qGMd;Rb8m`XDjF;2IZN7;ETSI`?1NEzdKPFg7{{Z85$iG zhu@5!vALy0)z5w`YUq!`my?W^Ok6wo|$*=St&AmzK^c{ zE{@m;=?_9(L`2ASgL~~9^dhFF50&nu`Q~pKu-{JOuUJ?r7qf-`}EV<``$W;7OC1;##i&<)?i9q&)soMES#| z*pil&|Ggw)Wzk8Cs1`}a8U-R#{0dNK+l~C`sN9sqFh23RWP!YwHVt~52!QWVfNh4y zNpIBzQbc#CbcOWV6IpCUUlTYdNXv;SJfJTR9RUnI;{rb3LP=P*c@My;?_=iU)NhqB zpy?5&D|cGKi`2UUrwm?D$`5Wdv(~{c+TPm5&+u*;X$>WedHmnKWq)Q;EJZ2#R6H~4KA6R+^x zVNwuT3O&qRj`Jzl;XLyExPda>8Tv?pr(eO#c9p8-rGp_(j&q{s7)kX zKGBvR*WNdz97%5V=icrXuV*Ly?|oI0I|*iKsJC{N>J6W7+YMyN!SiE|Pm2`MqQnv} zKit|R^s^46*l?t~xZs@Sam;G&6^F|7z7`c1uQgcYpFiCpL0(#b+=5OHBT`f2@(~|D zbYZHvaB_0B@@YF?cS zjk|vdNK6a#_I3?-7X74eiq}2WoIX!X8PBfH5L!A-84Bjrj(nJg6%-0WZgh@__+Wc7u z#l7=_ao~To`T-V}+RdI#SY*`JitC|yjuQ$K7M-6fXv>_9d?H{dPq2YgnNT09qcowq z{L6son**#SsQLno(i92gkIaTpFcYyKfA$~dv!8clNO)JBjrpvnqa_<|@{A z%#5`g@0!zn4c#|DZEHr4msg2o{v^%c5}-WS;Dlx2Q3*A{b{fXCM5qZu&l(2A9RSw} zgQNTkO$aOEq&_Ko2`j1`(ET@b(_%;_v?W*b&XvnZkx*E(X<|+G@~^=6UMQC?O=M3k3R8h?arLlV(F2Yu zcXkMEDEiyBgfXpuY$JRFCPC`EY;j*fFL)}|_z;=b?f9puZi>`CuVO%F1^EE?Y7NJU z{ADHnKLm?x1KkJ4?Qy7{P0qZO08Ui+8sTC{l~b%NmLuY$s_2b{9^_!J^R8h;W-h>A zjjkc9cP5^N245NM2!JzC=0+i7YMF`Fq(NWaa3bAdua=BO7eiE*WQ`$NEH-)2s&tb( z=I>^monDmS=2B^5l!;t(8#{x(hdNtiqSw>VC~4v0R&Zm4n89WS(%4H%&OlR}gKbUm z7n=^CrVBU}+{`D}=x?~y2w|Fph!_>;&*-bhJCd(e&#pq5*Q6^8!?yh5UpGq>9cIG~ zC%&9M$bGgjODs+pvnTqNd<10QL0r^ND?NTBbln?YRLq?;c_)c&Z%V~Y07kfsTvla% zo6>=6mQlkK64qQ_df0aOKVC7mtL4qQzPMGjdAzGH+GZk=ImtRWjG0vL|4_Rnt^HDH zLP{>^uZb?U_}Na$RZdo&ya46CcklsPTfg`PB~E%yjCGJrTWUy!`NaC|af7|=f&yJD zK2~&FZES_Mxw=8hDxk5+cM+9fztyoyGHt!riP6gQjDx-iNkfV;oD=F#L%1uI+B5Zj zfjWw#59I220@khyvTFoxoqS{RhDG8B6-n>ScHPV!m6O-@?6HG2wa(_xJR)x%>;)g!Fm*7U9LVYIm-o?Xy z)wY8AXy+sO^@a84Un){#?h4z7Guk41Ji<}PP9aO6U&3VME0dHy=|j1%*5D|Pza2Z! z$!2YzN1UKE0VBnvQO7Qh!zWZ!_4Kqf9S?Ja{Ar_q!&go_4>Q})THk%&$YG4b`OmC< zp_PSo0)o&Iw+~FE_@V$5H#&kvh{k&~L*>Z#I&pd7+&PJvY{905L}41Tg4XT^D}X;A zy>;VKE9J`;4B2-{W}bz$HG9ps&6~L7^X+61{RGr(2mJC8#Q5lF>B-&0+LQ%BIsD&# z<9YOn91oIRc)6im<|ON-NaT`H2n5D73<@2bi?m9bsI3XuOr+Ar=#M?Z1#*)ugrX`o z3=2d3eMiV9=15=dtQJUG9D!OQKLnb*;e4Vo7edfPe)lI`R_{jV+kF)bXAXXI^m0|> z!wowfdS^eOrsk5e(QU0=RZwhfBU+tm)#0C#s><})M&o9iIX_>4G^~kD3S~PdSDo6i zwCq|`dY$a}`_}xWgRHf*t-pB{Yg?S4a&ye>b>8o}NI1JywSwhlIIrE5vc0`-Jpkja ztd@VgZ7egKJ*+)Ot>knxYyCF8t-IRT`GnoOydbJAcXcO@SF@hPF$IOvMmmcUix*nO zdi#Sk&dh0@R=Xu0|8$D&eOArR*KWQxd94ntwYDCPa(9}(rE_yP({w#bHo46WtaZjZ zH9K2{w1M{>xyUTgCsXgO__YCyksNA0B}+}m3D#USl67Nbo@d{a~4Jw1#;FG=kI;>(4d?8nUQKplN}wpqapJf zlhaWa#+B98%;AWiq4feA`fw}0I8AqgC*|B!yAW^IfJdV&bsV;;Msy{tUFFF3(+mHl zTT=Ls?67>1GWZjF+30<&jRu&jPyqXq*Ky>2k=@%f6WxVQhJWE1S` zC4+B}nE%}PbTNhd|5m_2OjQr(y^$Qarc74c z>a*c|V(3DE2_gDs$vsm!++H+A7rwuBC2ziLb7azHU1?+j5~5R@;Mv5Ir(Ti3YeEGH zv=qi~Xs+G#Twe+=R@E?HJ1|a)=@?T3U*m34C2)o?55`ikkDb$lr`KnS`j-V95q!=> zIi`MPX)8Xh#D)9Q$l(=m72F9}Sz5OD2r3MZVg&1l;4MEYDM>D`q?Kcbf@nVB+4B`y zf2t4VMdatTLx}Ut>B(c3P9vyLP$#A3x5bFk7W@@?4c8h(bQ`%vCcpt$$)$4~H+Z9I zcUq2MQ3Rc5iv*tJuaq?Y4Ww~p&~U}bWGZB0)?>_ksyjfaUlnoSZL3&50tsBUQ_#xpUQ&h-}fNj0@I;z z?dDI4`(4R0UbwUr*q7o=t3=sK^uGFT%@@o%fZs7xIFi-yiR(`=SW0Bc+oYankVkb7N4VxXFR%^ zo4m?ndiK+O_R(uevJ{_xypR)7fHdcG2r2TDt%~>Oxh8S7|I*cfWtudIA$l5>+lX$z z1t7rRd##(l!}PvH2OczzC?tHQg=p|pKse_;@jdx44Utsf6KMe{kF_Jaj41wBC9T?n zp9vNc&wKq17FOwvYU@#%8O_+GNEs&@XG!5r&+X|p8;9)h!++D}6r_b-g7NsB&%Bwu zy$a&^nUz$dCQ{%K2GsD%JrK#LXV~E|$vwc4X z>~{_me}%P25xdG6!6FXIS(IKP$Z)ve2y&jew&VsyTiG2^Z`8jdzmxRdqi<2KhMheN zo)Sa`o*=E30{LD#j9@-oSwa+YN<_8)zZPKhE%O^FWf8G8Trc!EF8o7H8eCkPae=~F^-Q~XwSc_l5N zfg@rk+-~^tuv%z(!2j?VL(}n4LOpr!SPY;W_-o-j)C^QlK(_@QRhhC(do+hiCf{*7h{6vyb|qS>@VM4 z+qRQ1B{geBBXYC%Vd3!FakMko?>w*a?|>r}r4bV=c5!ao~Euqz7N$TZqPh z$^w>+CV-axH@-3tNs?J5&fgTDlVd~?&6s|kirnU6RIyz|lvA2{)S>lVQcSi)Q+jUD zW_6!d?AYwJS*0bH3Qrptb{Oxe^xD22((Q&3k}-&yjBkCVuN8h+%(CI+;_C4HB*ek| z$znthr$4Ni(Q3KHDCf_k9=Kkk6Yfqhz>POFX8WxjfPHc+lK2QhR<{$95T`H;!9SyWf|VApTi5 z8&-1;{{?5kivrQ#Bi`OY`A*0n;$;2}nVj`RfhF%Y##{G~VLvG{ijxMf1rr1L{sHYA z?vStd_>DAfu*vun3q5}Ay>rot-sm1L`tF@j6OW2FWwvTqL4oO05V8*kV(6+%-vf%r z?)je+p^|m%8&7mP;WTM!SV2H!PS;sI zG$9PAZ0U7hGWOJ9zvs3dQst9G#y1~0NAG z58-19yBR7L&Gg<0M;X}=kRLFTfmTr=f!PWfYd7x++EK9Vy&}tX?!YSDBCG_Y`UFFV z96HiI(9N?M+`hE8_B38Jp`}Yik+bv?{95aQcB|)pos^hR{)r=k*);Fo2O9F4Wz8-yNRDmW_L~KRsE)d5=4N z8YsVN4Cx*bi+DoI`xg*C+2g6lo;QH*?mectFR-V;@G)Rn4GU+^c$EoLd9WpP4=((u z@=&Uh!|qw~Gb_fTehMAF5tZmwRngDPMrO8ZCU+?S=eXK#vhCwe&}$HU+@Ou1GmJhz zuDRA*qNbi$5|q1&tWg5BwR-%63r+CP9$l);{3I6yi!Y*v=HW9`=yv;flUsK0O_0hp zSIp@}*3;%jN&Q_c=vwBYfyJWJu$K$vA7V9dIMYrHYtiu&g-XgnYym;dV+I=HJG4Xf zerb%UAYEV-&EF_e!~TWr>C_-xvMhLH`H2&>t0u5lgiYt*v>d`1f4a>GE zT)QAGEzO3qTuWmoWS(Z&<(`Od^m?brm#Z6|Uin+uVMI+XL1^3KuT~%?4VITfZ#@J$ z!JWYzT0;^4jro2{k*D=&TI3Vq4Da?({0hXIS0oamdBlbrk z=c{=RgkrN<@gI4n{yJ|tPyN;94*YOWJE@K}p7upj*s0dq_wLxtBa?fmaZOd|aZ2y? zIa_);OLP3hewJ`Y@!>;52E7vp>7)-gvlQN+ zl>4Q8Q*VQc+dasu@sobjgIzT?dy&3gGOedFZF9wZf#=>YW5a$oZ146zak2aCh%TxA zU{}8z&xzO3_j``)dG`R(jH#A(A*?ALmnj6%OI3^3TBznm{bbjvd|~GXtP2&p6o_Db zHXO0nhjVA5oyS+Vwj2z%#*CJ?;#`iZ$N2n=DNuPAbTE|R@LuI`UWXLq{m+xBPPzL5 zh`3;AyuxW8F#lImmG?T_(9%Q#6iny37n*?y_p!#W*^d@}I86CB3W)y-Tud<$LGwnR_qB zM2%Z`wVwxLB>+8du}h;9j|hh3)}FT_@q14~ID6ip_;BiEBw~D?e$jGRl6ZkZjx(t` zX6Q{f7Jcu`$|ncy(Z`y9^6ZVuA!#M^c{j*Rod|!v776=gTa`w0GK>Ad z61barKKYyB&=rya7T<_pH%)`K4>cFl$#0W({v9k6f$mQMdBJr9470w*ak;X*UG&CF zL^z>1Pr+_dBm_Q=*n{-TS54ytFI@k^tsEF&V940ngSa%T%-2s5QD9O;u{{*6CgdYc(J0zv)c61|=vUIx zbKksREY(s>LQDNZ`bOBF)9?{2r4~p#baLi$`kd1>`d{TNc=ur`!@*}a?DFQc_qeZvOgE{=`HlZ!Kb+$`k_xAake8pZdo zi2nQn?-0vbw{Sn#;Lh2CFPQGIVTSb>Lm5Pu;S57+t3}XsjeHpS+oDqz@Ng%VNI;X8 z29H-awP2{Ixs-{a7@s#n4vt+{iNc1z^!cZZ&?4K|2(K+>O(>OuAtD_pNLvS+2yELB zdjn~@^ciImn3yrtP$d~$?CG9jSv(UrVp$Rd@)p{o{oM`bNwB+Oz|{80 zJJ<+$FwQGo5>jJPMK_q21GqkvRya7+aT`*XmI}N>dAsWoEA~X_?V`N8v^fkYWsqn3 z1!+*vClk(|3#Wyqn&G3`#0~U<1H2LN_McwzRSAb~$5FMhK`L&26m6(fW{B4X=Q^k^ zw7U$3XyAQ;88>@TkMzZA7k6Yz=#xj6_gp#M=O(lok0*)9ODywR&@eI?cqfq*5qq74 z(uxA5PXzg}BYNR^0-NzvuifJbp3Q;4SJOvlzinj1&fq0`1&b&X| zHj|KLrTpGoXBc;wjU$;)O#w@lx}__~KA{I_RRKqKVY59+7eE3tQNABEd8h43F%6(k zay16hv&1CwC9kD8xQUf8I_n*Rx^u+p)-K}6hfc8lqCQjtrAT&w(1CMAo_0n^%~CA| zLTHM)?kg7PPx9Kg2D?~DiYx0u@4q8#xHrjMk}GNH78wBJ_CCRpN|u?fvRu6 z`a%Ds023Fbph;e`Lf>NI)o_L6UN@G2&M0UTL4To}T7i~rVjqpf2xfy#3tlo;*fG#gP7O}$%kaDJA(+;!0PvHCWcDG&kihypr zZROwIlXgpM?QB=1*`K-4yLw-bh$U2@Bi7X4+$y?AWMSDvO+HRX6%ol14ZeDUs@kfm(3~X>*ov ze>5*~h3-fM6nIY9Eyjf7w22jNbGZI;`A8OwWqwROuDpeA; zUg@(YV{yPean8}?&#N?Btz?xL@dctyA%}C91CpAV; z7Fpu95xd;Wd8DJvQlcuXa-&?AlcLK(Dur>wA2ix_uhyI~v5IY*{X}CHYQ)c4o&5-~ z4%W~cr?_^*MZHNk`zzZSbi?82u7->90#a z4P3g3;kb{d^?YT7_go2nV=HhmHPIGqJlV!2U@%B?r#x@-sU3bLUAhs62IVulTn&X; z)mcV||IXw09yesSU%O%+t>sF97_R5Fu#&+Z|9jvanZYUscW|!M}|Jbbf)60uC4~6uYTWGIR{7kQ z-uephHqm&?VHjCk)BcMy!yhUtj<4JjY_Cs5!<|sEkBG8w7x} z5zR7}j1Eu<!DfS}mJs~Xl!jeIa?Gsns@>!_(aAcDyZ}s-I@18Vgq>c+ zg3p-ob;eCv!Ytux`(b%LeMP>%1aINXtzm`?79p9YSFbtF$68^S>9W(y%dYEauH{2q zQKi7WEOhs0TewXpHOpNqJ^1LAXwl2P1B{u9QlemCOp)|8&{z}m$G8)|&VcchF&Qe#o%|3-uWHOz1 z&mYDC!vvFJ56)=>IzK)SU0cDy1JT91jboUV$G!2`-F)#__$rKIqpqeNp7n-vNXa&z zz2%<~jMq1?;Cf7;=V6SP_KhE8c`9-^ z*Ff<$%9#$aI-e6w!udKsoEN?WTxAzTJAJpzawzD6B?8E~`Nu1b$HK{$rgzsnlbFPn z1ME;=zY^x7?@A#U;txa-8I6Fo+qj$ud^(_Q1&f(H5B=1s;pYT%j#N=>9mMQG0rMQ0 zW0#`dxHn*n+gK*_{MM;Fa-d-vPeya%B6>rT$voiLQvjS^|J5=HH)}6j`p8Xzp>!7k z=-TkJ!i^sdRUrx=9sLi)jC=?+lKw+?^6#lI)4P+K_Us-v{;dw;%=e!(n*U{tjV(wdQ>Qt-iub8`h0qw;3RhE*4;?G1Bt-;bE} z$3&|TxQQt=2JJikDJO1Ag+@y{N)qH!C!EQ+>qDxrN7C*T8~R8CC2TKL8%CauLjYy#k=&FM;x1f{lWUd=(eIH+lAfl#$6%?2sm zN72rLZmc=8_*CMim~*4o=HFR=Tm%wjh3%Uo_=c*__PJo`i&ytshaT#1)`mX4?1jiD zcQ31m7M*n*+}wI7HxU6(e9R}`(TX@@WM>!FS8ZlD;|}W-iJ=$FCBWEA z$c2^d=TS|0I#Q0ER+h0@3CJWIWa=?`0Ar}*gNf4x=Imtwnjks=r{5(sJ6D`O_gyLs zzj_Jl#yPc-mJUv~bh+=0(U2%<=YGx0EtR?zMA9~f2_w^8I#L$exUpc zt9h}deWXA{Z#%ZZ9wcAIPhIooSn1Cv$|lj|#n}Ih>pANjv9#V}|hl zR61dv2_d*DSvk?)(297pUJNHiG`{TkceqJGYq?-Zg(ET3{#$0I8^RR@%ba=vhT7hY z5OQX44~^6sZ~7W15di;j;={x_~qyHoExDxg~2@)utyFb5p;9ZL~Y zm{ZqSx`$#ER{d?`9{H##lkU)o(RIOOj~?!-drg@Nn-*gPZ@0_nIJZQ&Ax4w0Ktzj} za3Ic zPjh-$;jB!!p0;vDU5{Rc-`HsLUh8lk4J=ID-J)1FLHJ`!JQqsX__g9$GOujbc90jM zGuiU~Uv=@$3^5#;W7$UaxP}O>M}JQaN~8bo-_tgUd0qp%^z`#(sp*{=K**vJ*HD2& z5W~Ufc2jx%v_9S|=~&btmEWAOn#sRdQzJ1JU6EN2QF($VT5d$UXfX}=gZ33e^dD$8 z45VzcN)f$LHX(Ez!wTsqvwg<@X6%3zDb7oMF5fS5hLtK6n2gm00Cif#mD82sSW{8Z z-E8kiHu?GlA@;*Qr9b>^Vx?@s*cg1rMjcqOG0rz`f@fE-c?Bd8mYo~hA+r9bNpfL=kq0AAN9Z< zl%uGUc3e2AHW3tf=R|}ZArP_z#R_lDc&+)-T5UpsvT&l!X8EUz3IgWz3zfx3odXZx z2QMsx9}sahOboalI?!bmX?PRdjm|T+qCExhnZh7N72wd^(*5g>ZXYY$+>6mQm`NjvwZt zZ>xHmFG$U*19~(U=QZ0u*bq&BKwsoN!EW6DP-Q#)-kz*}0}-W{jHby_k3;{j1^4Q0 zn9x-03oFhQ54Hwv>dO=rX)*`%3KrJi?ZKPu_Crf#vD)>n(rpLD9g}{hW~&$H8fTs1 zfyPKhSv%oxqPO(I!kE!|!ur-lHqMjK%=CPnjaz@h%zL_70&%wNc@>xEr_HjAchOwG7S=46X{yvGKAr$x*){LT&2sK`{5iyra;Gc0TtUEe?Cmc zZt)m?GXDC~xu0f7o9*h1IbA^9Js`kXUz)=F!?(Ak`-z++Jk?mHCYEl#jm5Yo?gwDY z_&RyRgKN_@tlMu_tT;Q_)aKid>by{k`A}owyF8NE5rgUUBmF(=#5V>Q7{G)KNK}pG zKu+e-JqyC8EW#5gCKLwkejXy|W%Z0mer9~$;#Lqc$`2FyebwAd5<7rNKAS#4p+Dh9 z#OYS8F*n=xafTfWW5=uU@0&Y2qW>}`?U@P~{b}4Ku?iRi zDxNd;dLDNx`#951_k9^V%sY#IA<3qq`_Uer#D}#M25+hMgLVYAAYCXO@}CT?c8PYH z9w~u{`Qi?~-IW~ zBL!To(BX@Si-PTvbHW-4lDupSO;#ePVMV?wjcq1o=~Cr?I%0qRPKfuer?W_!r+ECB zUX?nIm^a2;Bj#T_=? zSWDe+#Vp5!${){rThV@bp#374Z4@U3-L+Ba;d5u6ZO~`>n>ZqG_F?@D;%$mCpd6ZU zNpU+B8p%0ioh0Q*+Mqo0^btnPDP4FL`v zF$iRc(AHjh3AJTSCu%ZniMe|G)<_st4uFG;Cdx#<5h0`*Dn7sG3 zbVlEY=^fSy(FVci)rku$>fgD-bV_X7H&!$)#9DWij}glx;>%GVcF&$-I!a|7{|Qlt zuwK;t&;(cz6)m6AWI9y!U69*9LCd53f4P26k^V125^ycBtXC_C7Q>j3A#LdTQU{;^zp=p}_A*5Ey@?#`a7wwtl>fwX5TE9ma z1)MTdI1v$Q^wNvYjLQ(9Pw4A7{*}#Svi{XXI~)J@*X5J{Q`2rck%V2TvmjAO*Aq@h zR2kkLx5b%%#n}VRO-o;MROYN#w8NZmlWH=HuI*VV(Gz6w_!)Z`*$!D^dQ|_ya3{*c z<2Ce{H$03TEZ$mr^_jZAufQ{d6UVNhjNwq>WK{_3W8SP6AeKl|?GS75=(-{1vifR$ zJ%Y9tYreCq%!|^CXYzMWiWB!3kN;HTfbVnr{1>kRemF8=Uuhe)d3e#+pW{Q)?mZ7y z9;DxGm6#w8xm3tFd<)O}_()3bj!(*Ekx20!eX{nnSb!MxZAsDKdQiqCSx%*mL z79*|Fv(s=%JSq#F#MK?fg43ZvZE(BGvtO&e{ms#DN-#Rxegx?NM~}y4`|taMn?-{Q z3U^=#skS#Aa~@(%{EuQ3El|jXbar5Zr>bcFA9N9sA!Iee&5w3-KO^`;pXA3m?ZAF$ zfl+uNF;bUsWNhkR{B5TRlPyPM5iSTPbh!T@xDGN{3*p6onY9ToxWkX}@c)%|XZe5a zo%ui1+aJe;O2`tjrNPj*`gTnkmn@Baq^zlQDSLM;gAiuyYYnnR)+|{@UAq_)hDa1M zgJh{0WX2L=OoPD;?&tRXFTRg^emv(q9_Ml1kFz~q=ly)Y;Z-CU7{{RrraA8?r$Ix1 zO!?bIt0do%$cd*}|Iju+tHfGpY4m4 z#io?mpZV)bwxW&QLfJ5%J{6`>je4y$bT;9++TemN!m?smx{0svXB8+@hqR~g_8?u_ zl~p-XddNh})F4=Uk-STJ#D4t5ev4--w~nrwHHaG5X7g?DwYFk$T@0!EB*BgUDis&O zzZW_>6mc&v1{yU3cH98NrBO?3fFm`dk5Rj@d3mtnmOE=zVq06?rBHERgWI*OQ)u^)kdO`MjyEgq z2eU%aoUjVZs{xC!1DU2fnUXB0YeHrttLoxcAZ|G$d?{_<4~e;k<38#b(hmPSS&v~% zgB1ob3lruZv8{HodyagqP$@CvUZvndi&*I$Eh+Gqs0+z66)r#)So!IPvA*nui^Ug? zB>czgyzopaXmKYunplXCnRsq`j|NEjAq<6ZHYJxPS0mP>4CK2$F{CN6H*A(=j5euE zcCNKzmm|D_Mn9-X8hzLM`oacOqJvp#-i2{sL*8bIaj%|09$Bbz%V;LxOqi?g~V+2-n>BF{&pp)bQo0!Vv5j=m8f_(fi`LEIv1duh(*Y4Wk zW~@oG-{ki>1cz*T#bu7rPto*E+DDDWYAvsn>`k}+c1cMT+h@ThI z`}FGa8c7P7n(7or-%JXS-TtA@tJi}<`cxx)*Pg;RzCb=Jbn`6F95EaQ2%zJORI@SJ z!=s*H#hKUKCk_ouI=y$Qyb3a9N;VqXzZ?pmKyU0G(|dnjrSzzh3ndHt z-e55*!d^75n{=_xai1M>UFH!(v)r~a+5JCqY z`|{i2L_F$;@$%yk`igN{V~AmPY`4Fvlr6e=j1eT1+2I_IN593Hz}3HGBq2jk`*n^4 zJ*OtPhE^-m96*O~NXsQ2^<6LP)yanNq3J6W93xP@|DGJpTsL|t#?NFgS5@I!`q5Ji zK0JsZ@jgw?bo@J0?5-R#s8slq#+&OaP{kWPaJIraKU>fRK z55YE)Ug&jxak%bUFCnc|Qz=4w7e?we=pqpzGcyeLXdL=voPG@bKF`X!lLebXw>L{i zS2xXwH(j$a$ZG2e6^{AcF3-dH=nee0>bz0UylG^Qo|mjRe(5TIRsS6K{(5=hos_n{ z{NQJWp92fqg0Tnu|}tXV^6-jNO9=RZH!)||2S)BO)GH>_rakqON-gQ4;kF|@@;d=dC?y;)um~} z^wm3u7qu?iFn>g3pA(L&0UQ4o3ij~6_N-e{xobK5G*HwJX6$()BXLrSxwD5-(MiDa&7`A`e9P5|kslV|XTs*>eJU2LEb7w) z5jL3esG)$)u}JJ-34tk+|8hghg5z{S%O^Ra&qfT3i^jQshG)?u`Ovg03$~2CZDKs; z=0F%|vY~O6?MGN8muR?k-qr@#v%tepR~eXk$b6ab?YkVDLW#UQfeV*@^u}i=XKU5j z+f$&|eu89S?O$A6{1y0RYxiR1)ZWNm0;v2q*CEBx!GQOa^;+kiYDwmV8UeMxY2UBb zHAPyC({EWM=fZc0Q0S<L^Lu*wF0A{JQ}US?SoD8%>PY$GV; zZs*tL+GI>$3s&EC%1ubcvfHWe`C@@L^aTA+`j9_+&^jN-abT?*dp_7eyI`Xm}m$KqbH4Z*)cENRcNQSxlfc4Q^!0vEd+kS-c6^~i!`#l zFKU>&neQVlZrYDpiR_NXWiNSngQG-^#RiAEdVKT&2?3JdTo3V#YO07*+Ort<{jA|- ztIx?cj~>x^avB-WkUp5NU8NjAOj<4t1AKBl_CDcltih#s3zx6hk$KM_`rlwM+ssW7 z$(z#+j;^E7I7P86R;z5G1!8(sAb^^cCXSg=@-LS3zO3?;>l-osj|Y{qNorjR&gdX0 zU|x(9*b#M_MK!3<_EDZc5u9^BdQ!X9?m4<4Evo;G=#R;ka6rlOKOSfBv$DkD&v#|s zZdf?ZU3J)9y(I^iNQ^!63w>4wUL2cCM%fVZ*T>88yg&qS0PV{-Q7Zb2>J?B@HTVVl zi5Xoz23(E*G>YBe1;oZ*{jzy}%>$_Yx7)u4`TtrW7XalD^lEDV9wHR(!~+y_Q!A4? IBbT_p0jSuq(EtDd literal 0 HcmV?d00001 diff --git a/src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_light_2x.png b/src/legacy/core_plugins/kibana/public/home/assets/welcome_graphic_light_2x.png new file mode 100644 index 0000000000000000000000000000000000000000..034e8b87ff0f5bdafccb49bbd68d988b342655b6 GIT binary patch literal 53122 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 a#-9q>E7DL(mf6?_JP6m5uySX= { - const addButtonExists = await testSubjects.exists('emptyDashboardAddPanelButton'); - expect(addButtonExists).to.be(true); + it('should display empty widget', async () => { + const emptyWidgetExists = await testSubjects.exists('emptyDashboardWidget'); + expect(emptyWidgetExists).to.be(true); }); it.skip('should open add panel when add button is clicked', async () => { - await testSubjects.click('emptyDashboardAddPanelButton'); + await testSubjects.click('dashboardAddPanelButton'); const isAddPanelOpen = await dashboardAddPanel.isAddPanelOpen(); expect(isAddPanelOpen).to.be(true); }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d957e451fdb748..83ef497e50649a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1773,10 +1773,7 @@ "kbn.context.reloadPageDescription.selectValidAnchorDocumentTextMessage": "にアクセスして有効な別のドキュメントを選択してください。", "kbn.context.unableToLoadAnchorDocumentDescription": "別のドキュメントが読み込めません", "kbn.context.unableToLoadDocumentDescription": "ドキュメントが読み込めません", - "kbn.dashboard.addVisualizationDescription1": "上のメニューバーの ", - "kbn.dashboard.addVisualizationDescription2": " ボタンをクリックして、ダッシュボードにビジュアライゼーションを追加します。", "kbn.dashboard.addVisualizationLinkAriaLabel": "ビジュアライゼーションを追加", - "kbn.dashboard.addVisualizationLinkText": "追加", "kbn.dashboard.badge.readOnly.text": "読み込み専用", "kbn.dashboard.badge.readOnly.tooltip": "ダッシュボードを保存できません", "kbn.dashboard.changeViewModeConfirmModal.cancelButtonLabel": "編集を続行", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2e47c7a615e364..87c11adcb5e777 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1774,10 +1774,7 @@ "kbn.context.reloadPageDescription.selectValidAnchorDocumentTextMessage": "以选择有效地定位点文档。", "kbn.context.unableToLoadAnchorDocumentDescription": "无法加载该定位点文档", "kbn.context.unableToLoadDocumentDescription": "无法加载文档", - "kbn.dashboard.addVisualizationDescription1": "单击上述菜单栏中的 ", - "kbn.dashboard.addVisualizationDescription2": " 按钮,以将可视化添加到仪表板。", "kbn.dashboard.addVisualizationLinkAriaLabel": "添加可视化", - "kbn.dashboard.addVisualizationLinkText": "添加", "kbn.dashboard.badge.readOnly.text": "只读", "kbn.dashboard.badge.readOnly.tooltip": "无法保存仪表板", "kbn.dashboard.changeViewModeConfirmModal.cancelButtonLabel": "继续编辑", diff --git a/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_security.ts b/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_security.ts index c7a9764c6fb58e..aa6860b35763f8 100644 --- a/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_security.ts +++ b/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_security.ts @@ -107,7 +107,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { shouldLoginIfPrompted: false, } ); - await testSubjects.existOrFail('emptyDashboardAddPanelButton', { timeout: 10000 }); + await testSubjects.existOrFail('emptyDashboardWidget', { timeout: 10000 }); }); it(`can view existing Dashboard`, async () => { diff --git a/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_spaces.ts b/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_spaces.ts index 127141b156cd80..c1197fa7023c51 100644 --- a/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_spaces.ts +++ b/x-pack/test/functional/apps/dashboard/feature_controls/dashboard_spaces.ts @@ -73,7 +73,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { shouldLoginIfPrompted: false, } ); - await testSubjects.existOrFail('emptyDashboardAddPanelButton', { timeout: 10000 }); + await testSubjects.existOrFail('emptyDashboardWidget', { timeout: 10000 }); }); it(`can view existing Dashboard`, async () => { From 8992a43c6e4a8d3f1a55b20c520926e817c14a2e Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Mon, 6 Jan 2020 11:11:18 +0000 Subject: [PATCH 3/3] adds strict types to Alerting Client (#53821) The AlertsClient API currently returns mixed inferred types instead of a clear strict type, making it harder to work with the client's type signatures. The root causes for this difficulty is that we have to support the SavedObjects API which allows partial updates of types, and the implementation of code that converts the SavedObject from a RawAlert to an Alert in a non type-strict manner. To address this we've added concrete types on the AlertsClient APIs, using Partial on update due to the SavedObjects API, and a strict Alert on the other APIs. --- .../plugins/alerting/server/alerts_client.ts | 88 +++++++++++-------- .../alerting/server/routes/create.test.ts | 18 +++- .../alerting/server/routes/get.test.ts | 11 +++ .../legacy/plugins/alerting/server/types.ts | 3 + .../routes/__mocks__/request_responses.ts | 2 - .../lib/detection_engine/rules/find_rules.ts | 9 +- .../lib/detection_engine/rules/types.ts | 5 +- 7 files changed, 90 insertions(+), 46 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index fc0252c86fe50b..33a6b716e9b8a1 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -15,6 +15,7 @@ import { } from 'src/core/server'; import { Alert, + PartialAlert, RawAlert, AlertTypeRegistry, AlertAction, @@ -69,28 +70,26 @@ export interface FindOptions { }; } -interface FindResult { +export interface FindResult { page: number; perPage: number; total: number; - data: object[]; + data: Alert[]; } interface CreateOptions { - data: Pick< + data: Omit< Alert, - Exclude< - keyof Alert, - | 'createdBy' - | 'updatedBy' - | 'createdAt' - | 'updatedAt' - | 'apiKey' - | 'apiKeyOwner' - | 'muteAll' - | 'mutedInstanceIds' - | 'actions' - > + | 'id' + | 'createdBy' + | 'updatedBy' + | 'createdAt' + | 'updatedAt' + | 'apiKey' + | 'apiKeyOwner' + | 'muteAll' + | 'mutedInstanceIds' + | 'actions' > & { actions: NormalizedAlertAction[] }; options?: { migrationVersion?: Record; @@ -146,7 +145,7 @@ export class AlertsClient { this.encryptedSavedObjectsPlugin = encryptedSavedObjectsPlugin; } - public async create({ data, options }: CreateOptions) { + public async create({ data, options }: CreateOptions): Promise { // Throws an error if alert type isn't registered const alertType = this.alertTypeRegistry.get(data.alertTypeId); const validatedAlertTypeParams = validateAlertTypeParams(alertType, data.params); @@ -199,26 +198,29 @@ export class AlertsClient { ); } - public async get({ id }: { id: string }) { + public async get({ id }: { id: string }): Promise { const result = await this.savedObjectsClient.get('alert', id); return this.getAlertFromRaw(result.id, result.attributes, result.updated_at, result.references); } public async find({ options = {} }: FindOptions = {}): Promise { - const results = await this.savedObjectsClient.find({ + const { + page, + per_page: perPage, + total, + saved_objects: data, + } = await this.savedObjectsClient.find({ ...options, type: 'alert', }); - const data = results.saved_objects.map(result => - this.getAlertFromRaw(result.id, result.attributes, result.updated_at, result.references) - ); - return { - page: results.page, - perPage: results.per_page, - total: results.total, - data, + page, + perPage, + total, + data: data.map(({ id, attributes, updated_at, references }) => + this.getAlertFromRaw(id, attributes, updated_at, references) + ), }; } @@ -234,7 +236,7 @@ export class AlertsClient { return removeResult; } - public async update({ id, data }: UpdateOptions) { + public async update({ id, data }: UpdateOptions): Promise { const decryptedAlertSavedObject = await this.encryptedSavedObjectsPlugin.getDecryptedAsInternalUser< RawAlert >('alert', id, { namespace: this.namespace }); @@ -257,7 +259,7 @@ export class AlertsClient { private async updateAlert( { id, data }: UpdateOptions, { attributes, version }: SavedObject - ) { + ): Promise { const alertType = this.alertTypeRegistry.get(attributes.alertTypeId); // Validate @@ -287,7 +289,7 @@ export class AlertsClient { await this.invalidateApiKey({ apiKey: attributes.apiKey }); - return this.getAlertFromRaw( + return this.getPartialAlertFromRaw( id, updatedObject.attributes, updatedObject.updated_at, @@ -494,24 +496,34 @@ export class AlertsClient { } private getAlertFromRaw( + id: string, + rawAlert: RawAlert, + updatedAt: SavedObject['updated_at'], + references: SavedObjectReference[] | undefined + ): Alert { + // In order to support the partial update API of Saved Objects we have to support + // partial updates of an Alert, but when we receive an actual RawAlert, it is safe + // to cast the result to an Alert + return this.getPartialAlertFromRaw(id, rawAlert, updatedAt, references) as Alert; + } + + private getPartialAlertFromRaw( id: string, rawAlert: Partial, updatedAt: SavedObject['updated_at'], references: SavedObjectReference[] | undefined - ) { - if (!rawAlert.actions) { - return { - id, - ...rawAlert, - }; - } - const actions = this.injectReferencesIntoActions(rawAlert.actions, references || []); + ): PartialAlert { return { id, ...rawAlert, + // we currently only support the Interval Schedule type + // Once we support additional types, this type signature will likely change + schedule: rawAlert.schedule as IntervalSchedule, updatedAt: updatedAt ? new Date(updatedAt) : new Date(rawAlert.createdAt!), createdAt: new Date(rawAlert.createdAt!), - actions, + actions: rawAlert.actions + ? this.injectReferencesIntoActions(rawAlert.actions, references || []) + : [], }; } diff --git a/x-pack/legacy/plugins/alerting/server/routes/create.test.ts b/x-pack/legacy/plugins/alerting/server/routes/create.test.ts index 03b33b0bd40b0d..2a0ae78fd78b22 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/create.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/create.test.ts @@ -20,6 +20,7 @@ const mockedAlert = { params: { bar: true, }, + throttle: '30s', actions: [ { group: 'default', @@ -44,6 +45,13 @@ test('creates an alert with proper parameters', async () => { const updatedAt = new Date(); alertsClient.create.mockResolvedValueOnce({ ...mockedAlert, + enabled: true, + muteAll: false, + createdBy: '', + updatedBy: '', + apiKey: '', + apiKeyOwner: '', + mutedInstanceIds: [], createdAt, updatedAt, id: '123', @@ -71,8 +79,14 @@ test('creates an alert with proper parameters', async () => { }, ], "alertTypeId": "1", + "apiKey": "", + "apiKeyOwner": "", "consumer": "bar", + "createdBy": "", + "enabled": true, "id": "123", + "muteAll": false, + "mutedInstanceIds": Array [], "name": "abc", "params": Object { "bar": true, @@ -83,6 +97,8 @@ test('creates an alert with proper parameters', async () => { "tags": Array [ "foo", ], + "throttle": "30s", + "updatedBy": "", } `); expect(alertsClient.create).toHaveBeenCalledTimes(1); @@ -112,7 +128,7 @@ test('creates an alert with proper parameters', async () => { "tags": Array [ "foo", ], - "throttle": null, + "throttle": "30s", }, }, ] diff --git a/x-pack/legacy/plugins/alerting/server/routes/get.test.ts b/x-pack/legacy/plugins/alerting/server/routes/get.test.ts index 5b1bdc7f697086..320e9042d87c59 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/get.test.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/get.test.ts @@ -29,6 +29,17 @@ const mockedAlert = { }, }, ], + consumer: 'bar', + name: 'abc', + tags: ['foo'], + enabled: true, + muteAll: false, + createdBy: '', + updatedBy: '', + apiKey: '', + apiKeyOwner: '', + throttle: '30s', + mutedInstanceIds: [], }; beforeEach(() => jest.resetAllMocks()); diff --git a/x-pack/legacy/plugins/alerting/server/types.ts b/x-pack/legacy/plugins/alerting/server/types.ts index a2390bf93d005a..62dcf07abb7bdd 100644 --- a/x-pack/legacy/plugins/alerting/server/types.ts +++ b/x-pack/legacy/plugins/alerting/server/types.ts @@ -65,6 +65,7 @@ export interface IntervalSchedule extends SavedObjectAttributes { } export interface Alert { + id: string; enabled: boolean; name: string; tags: string[]; @@ -85,6 +86,8 @@ export interface Alert { mutedInstanceIds: string[]; } +export type PartialAlert = Pick & Partial>; + export interface RawAlert extends SavedObjectAttributes { enabled: boolean; name: string; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 2e16f209acfb17..edf196b96f5d02 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -283,9 +283,7 @@ export const getResult = (): RuleAlertType => ({ ], riskScore: 50, maxSignals: 100, - size: 1, severity: 'high', - tags: [], to: 'now', type: 'query', threats: [ diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/find_rules.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/find_rules.ts index c1058bd353e8ce..5f69082e3fc719 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/find_rules.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/find_rules.ts @@ -5,7 +5,7 @@ */ import { SIGNALS_ID } from '../../../../common/constants'; -import { FindRuleParams } from './types'; +import { FindRuleParams, RuleAlertType } from './types'; export const getFilter = (filter: string | null | undefined) => { if (filter == null) { @@ -33,5 +33,10 @@ export const findRules = async ({ sortOrder, sortField, }, - }); + }) as Promise<{ + page: number; + perPage: number; + total: number; + data: RuleAlertType[]; + }>; }; diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts index b0578174e1f658..4f4c0da7127cd7 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/rules/types.ts @@ -35,10 +35,9 @@ export interface BulkUpdateRulesRequest extends RequestFacade { payload: UpdateRuleAlertParamsRest[]; } -export type RuleAlertType = Alert & { - id: string; +export interface RuleAlertType extends Alert { params: RuleTypeParams; -}; +} export interface RulesRequest extends RequestFacade { payload: RuleAlertParamsRest;