From ceb8595151768601f5257ec8d7bb2163328acf59 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Tue, 30 Jun 2020 10:28:54 +0100 Subject: [PATCH 01/13] [Logs UI] [Alerting] "Group by" functionality (#68250) - Add "group by" functionality to logs alerts --- .../infra/common/alerting/logs/types.ts | 103 +++- .../utils/elasticsearch_runtime_types.ts | 18 + .../logs/expression_editor/editor.tsx | 26 +- .../alerting/logs/log_threshold_alert_type.ts | 2 +- .../group_by_expression.tsx | 85 +++ .../shared/group_by_expression/selector.tsx | 56 ++ .../lib/adapters/framework/adapter_types.ts | 1 + .../log_threshold_executor.test.ts | 572 ++++++++++++------ .../log_threshold/log_threshold_executor.ts | 292 +++++++-- .../register_log_threshold_alert_type.ts | 9 + 10 files changed, 918 insertions(+), 246 deletions(-) create mode 100644 x-pack/plugins/infra/common/utils/elasticsearch_runtime_types.ts create mode 100644 x-pack/plugins/infra/public/components/alerting/shared/group_by_expression/group_by_expression.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/shared/group_by_expression/selector.tsx diff --git a/x-pack/plugins/infra/common/alerting/logs/types.ts b/x-pack/plugins/infra/common/alerting/logs/types.ts index cbfffbfd8f940c..884a813d74c860 100644 --- a/x-pack/plugins/infra/common/alerting/logs/types.ts +++ b/x-pack/plugins/infra/common/alerting/logs/types.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; +import * as rt from 'io-ts'; +import { commonSearchSuccessResponseFieldsRT } from '../../utils/elasticsearch_runtime_types'; export const LOG_DOCUMENT_COUNT_ALERT_TYPE_ID = 'logs.alert.document.count'; @@ -20,6 +22,19 @@ export enum Comparator { NOT_MATCH_PHRASE = 'does not match phrase', } +const ComparatorRT = rt.keyof({ + [Comparator.GT]: null, + [Comparator.GT_OR_EQ]: null, + [Comparator.LT]: null, + [Comparator.LT_OR_EQ]: null, + [Comparator.EQ]: null, + [Comparator.NOT_EQ]: null, + [Comparator.MATCH]: null, + [Comparator.NOT_MATCH]: null, + [Comparator.MATCH_PHRASE]: null, + [Comparator.NOT_MATCH_PHRASE]: null, +}); + // Maps our comparators to i18n strings, some comparators have more specific wording // depending on the field type the comparator is being used with. export const ComparatorToi18nMap = { @@ -74,22 +89,78 @@ export enum AlertStates { ERROR, } -export interface DocumentCount { - comparator: Comparator; - value: number; -} +const DocumentCountRT = rt.type({ + comparator: ComparatorRT, + value: rt.number, +}); -export interface Criterion { - field: string; - comparator: Comparator; - value: string | number; -} +export type DocumentCount = rt.TypeOf; -export interface LogDocumentCountAlertParams { - count: DocumentCount; - criteria: Criterion[]; - timeUnit: 's' | 'm' | 'h' | 'd'; - timeSize: number; -} +const CriterionRT = rt.type({ + field: rt.string, + comparator: ComparatorRT, + value: rt.union([rt.string, rt.number]), +}); + +export type Criterion = rt.TypeOf; + +const TimeUnitRT = rt.union([rt.literal('s'), rt.literal('m'), rt.literal('h'), rt.literal('d')]); +export type TimeUnit = rt.TypeOf; + +export const LogDocumentCountAlertParamsRT = rt.intersection([ + rt.type({ + count: DocumentCountRT, + criteria: rt.array(CriterionRT), + timeUnit: TimeUnitRT, + timeSize: rt.number, + }), + rt.partial({ + groupBy: rt.array(rt.string), + }), +]); + +export type LogDocumentCountAlertParams = rt.TypeOf; + +export const UngroupedSearchQueryResponseRT = rt.intersection([ + commonSearchSuccessResponseFieldsRT, + rt.type({ + hits: rt.type({ + total: rt.type({ + value: rt.number, + }), + }), + }), +]); + +export type UngroupedSearchQueryResponse = rt.TypeOf; + +export const GroupedSearchQueryResponseRT = rt.intersection([ + commonSearchSuccessResponseFieldsRT, + rt.type({ + aggregations: rt.type({ + groups: rt.intersection([ + rt.type({ + buckets: rt.array( + rt.type({ + key: rt.record(rt.string, rt.string), + doc_count: rt.number, + filtered_results: rt.type({ + doc_count: rt.number, + }), + }) + ), + }), + rt.partial({ + after_key: rt.record(rt.string, rt.string), + }), + ]), + }), + hits: rt.type({ + total: rt.type({ + value: rt.number, + }), + }), + }), +]); -export type TimeUnit = 's' | 'm' | 'h' | 'd'; +export type GroupedSearchQueryResponse = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/utils/elasticsearch_runtime_types.ts b/x-pack/plugins/infra/common/utils/elasticsearch_runtime_types.ts new file mode 100644 index 00000000000000..a48c65d648b25a --- /dev/null +++ b/x-pack/plugins/infra/common/utils/elasticsearch_runtime_types.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as rt from 'io-ts'; + +export const commonSearchSuccessResponseFieldsRT = rt.type({ + _shards: rt.type({ + total: rt.number, + successful: rt.number, + skipped: rt.number, + failed: rt.number, + }), + timed_out: rt.boolean, + took: rt.number, +}); diff --git a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx index 9e4e78ca392fd0..295e60552cce50 100644 --- a/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx +++ b/x-pack/plugins/infra/public/components/alerting/logs/expression_editor/editor.tsx @@ -22,6 +22,7 @@ import { DocumentCount } from './document_count'; import { Criteria } from './criteria'; import { useSourceId } from '../../../../containers/source_id'; import { LogSourceProvider, useLogSourceContext } from '../../../../containers/logs/log_source'; +import { GroupByExpression } from '../../shared/group_by_expression/group_by_expression'; export interface ExpressionCriteria { field?: string; @@ -121,7 +122,6 @@ export const Editor: React.FC = (props) => { const { setAlertParams, alertParams, errors } = props; const [hasSetDefaults, setHasSetDefaults] = useState(false); const { sourceStatus } = useLogSourceContext(); - useMount(() => { for (const [key, value] of Object.entries({ ...DEFAULT_EXPRESSION, ...alertParams })) { setAlertParams(key, value); @@ -140,6 +140,17 @@ export const Editor: React.FC = (props) => { /* eslint-disable-next-line react-hooks/exhaustive-deps */ }, [sourceStatus]); + const groupByFields = useMemo(() => { + if (sourceStatus?.logIndexFields) { + return sourceStatus.logIndexFields.filter((field) => { + return field.type === 'string' && field.aggregatable; + }); + } else { + return []; + } + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, [sourceStatus]); + const updateCount = useCallback( (countParams) => { const nextCountParams = { ...alertParams.count, ...countParams }; @@ -172,6 +183,13 @@ export const Editor: React.FC = (props) => { [setAlertParams] ); + const updateGroupBy = useCallback( + (groups: string[]) => { + setAlertParams('groupBy', groups); + }, + [setAlertParams] + ); + const addCriterion = useCallback(() => { const nextCriteria = alertParams?.criteria ? [...alertParams.criteria, DEFAULT_CRITERIA] @@ -219,6 +237,12 @@ export const Editor: React.FC = (props) => { errors={errors as { [key: string]: string[] }} /> + +
void; + label?: string; +} + +const DEFAULT_GROUP_BY_LABEL = i18n.translate('xpack.infra.alerting.alertFlyout.groupByLabel', { + defaultMessage: 'Group By', +}); + +const EVERYTHING_PLACEHOLDER = i18n.translate( + 'xpack.infra.alerting.alertFlyout.groupBy.placeholder', + { + defaultMessage: 'Nothing (ungrouped)', + } +); + +export const GroupByExpression: React.FC = ({ + selectedGroups = [], + fields, + label, + onChange, +}) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const expressionValue = useMemo(() => { + return selectedGroups.length > 0 ? selectedGroups.join(', ') : EVERYTHING_PLACEHOLDER; + }, [selectedGroups]); + + const labelProp = label ?? DEFAULT_GROUP_BY_LABEL; + + return ( + + + setIsPopoverOpen(true)} + /> + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + ownFocus + panelPaddingSize="s" + anchorPosition="downLeft" + > +
+ {labelProp} + +
+
+
+
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/shared/group_by_expression/selector.tsx b/x-pack/plugins/infra/public/components/alerting/shared/group_by_expression/selector.tsx new file mode 100644 index 00000000000000..7a6a7ff77335b7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/shared/group_by_expression/selector.tsx @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiComboBox } from '@elastic/eui'; +import React, { useCallback, useMemo } from 'react'; +import { IFieldType } from 'src/plugins/data/public'; + +interface Props { + selectedGroups?: string[]; + onChange: (groupBy: string[]) => void; + fields: IFieldType[]; + label: string; + placeholder: string; +} + +export const GroupBySelector = ({ + onChange, + fields, + selectedGroups = [], + label, + placeholder, +}: Props) => { + const handleChange = useCallback( + (selectedOptions: Array<{ label: string }>) => { + const groupBy = selectedOptions.map((option) => option.label); + onChange(groupBy); + }, + [onChange] + ); + + const formattedSelectedGroups = useMemo(() => { + return selectedGroups.map((group) => ({ label: group })); + }, [selectedGroups]); + + const options = useMemo(() => { + return fields.filter((field) => field.aggregatable).map((field) => ({ label: field.name })); + }, [fields]); + + return ( +
+ +
+ ); +}; diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 905b7dfa314bd6..018e5098a42911 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -60,6 +60,7 @@ export interface InfraDatabaseSearchResponse skipped: number; failed: number; }; + timed_out: boolean; aggregations?: Aggregations; hits: { total: { diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts index a3b9e854584161..4f1e81e0b2c40c 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.test.ts @@ -55,7 +55,7 @@ services.alertInstanceFactory.mockImplementation((instanceId: string) => { * Helper functions */ function getAlertState(instanceId: string): AlertStates { - const alert = alertInstances.get(instanceId); + const alert = alertInstances.get(`${instanceId}-*`); if (alert) { return alert.state.alertState; } else { @@ -73,11 +73,26 @@ const executor = (createLogThresholdExecutor('test', libsMock) as unknown) as (o // Wrapper to test type Comparison = [number, Comparator, number]; + async function callExecutor( [value, comparator, threshold]: Comparison, criteria: Criterion[] = [] ) { - services.callCluster.mockImplementationOnce(async (..._) => ({ count: value })); + services.callCluster.mockImplementationOnce(async (..._) => ({ + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + timed_out: false, + took: 123456789, + hits: { + total: { + value, + }, + }, + })); return await executor({ services, @@ -90,222 +105,427 @@ async function callExecutor( }); } -describe('Comparators trigger alerts correctly', () => { - it('does not alert when counts do not reach the threshold', async () => { - await callExecutor([0, Comparator.GT, 1]); - expect(getAlertState('test')).toBe(AlertStates.OK); +describe('Ungrouped alerts', () => { + describe('Comparators trigger alerts correctly', () => { + it('does not alert when counts do not reach the threshold', async () => { + await callExecutor([0, Comparator.GT, 1]); + expect(getAlertState('test')).toBe(AlertStates.OK); - await callExecutor([0, Comparator.GT_OR_EQ, 1]); - expect(getAlertState('test')).toBe(AlertStates.OK); + await callExecutor([0, Comparator.GT_OR_EQ, 1]); + expect(getAlertState('test')).toBe(AlertStates.OK); - await callExecutor([1, Comparator.LT, 0]); - expect(getAlertState('test')).toBe(AlertStates.OK); + await callExecutor([1, Comparator.LT, 0]); + expect(getAlertState('test')).toBe(AlertStates.OK); - await callExecutor([1, Comparator.LT_OR_EQ, 0]); - expect(getAlertState('test')).toBe(AlertStates.OK); - }); + await callExecutor([1, Comparator.LT_OR_EQ, 0]); + expect(getAlertState('test')).toBe(AlertStates.OK); + }); - it('alerts when counts reach the threshold', async () => { - await callExecutor([2, Comparator.GT, 1]); - expect(getAlertState('test')).toBe(AlertStates.ALERT); + it('alerts when counts reach the threshold', async () => { + await callExecutor([2, Comparator.GT, 1]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); - await callExecutor([1, Comparator.GT_OR_EQ, 1]); - expect(getAlertState('test')).toBe(AlertStates.ALERT); + await callExecutor([1, Comparator.GT_OR_EQ, 1]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); - await callExecutor([1, Comparator.LT, 2]); - expect(getAlertState('test')).toBe(AlertStates.ALERT); + await callExecutor([1, Comparator.LT, 2]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); - await callExecutor([2, Comparator.LT_OR_EQ, 2]); - expect(getAlertState('test')).toBe(AlertStates.ALERT); + await callExecutor([2, Comparator.LT_OR_EQ, 2]); + expect(getAlertState('test')).toBe(AlertStates.ALERT); + }); }); -}); -describe('Comparators create the correct ES queries', () => { - beforeEach(() => { - services.callCluster.mockReset(); - }); + describe('Comparators create the correct ES queries', () => { + beforeEach(() => { + services.callCluster.mockReset(); + }); - it('Works with `Comparator.EQ`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.EQ, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ term: { foo: { value: 'bar' } } }], + it('Works with `Comparator.EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.EQ, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + term: { + foo: { + value: 'bar', + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.NOT_EQ`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.NOT_EQ, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must_not: [{ term: { foo: { value: 'bar' } } }], + it('works with `Comparator.NOT_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_EQ, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + ], + must_not: [ + { + term: { + foo: { + value: 'bar', + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.MATCH`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.MATCH, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ match: { foo: 'bar' } }], + it('works with `Comparator.MATCH`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.MATCH, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + match: { + foo: 'bar', + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.NOT_MATCH`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.NOT_MATCH, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must_not: [{ match: { foo: 'bar' } }], + it('works with `Comparator.NOT_MATCH`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_MATCH, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + ], + must_not: [ + { + match: { + foo: 'bar', + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.MATCH_PHRASE`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.MATCH_PHRASE, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ match_phrase: { foo: 'bar' } }], + it('works with `Comparator.MATCH_PHRASE`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.MATCH_PHRASE, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + match_phrase: { + foo: 'bar', + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.NOT_MATCH_PHRASE`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.NOT_MATCH_PHRASE, value: 'bar' }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must_not: [{ match_phrase: { foo: 'bar' } }], + it('works with `Comparator.NOT_MATCH_PHRASE`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.NOT_MATCH_PHRASE, value: 'bar' }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + ], + must_not: [ + { + match_phrase: { + foo: 'bar', + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.GT`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.GT, value: 1 }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ range: { foo: { gt: 1 } } }], + it('works with `Comparator.GT`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.GT, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + range: { + foo: { + gt: 1, + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.GT_OR_EQ`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.GT_OR_EQ, value: 1 }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ range: { foo: { gte: 1 } } }], + it('works with `Comparator.GT_OR_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.GT_OR_EQ, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + range: { + foo: { + gte: 1, + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.LT`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.LT, value: 1 }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ range: { foo: { lt: 1 } } }], + it('works with `Comparator.LT`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.LT, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + range: { + foo: { + lt: 1, + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); - }); - it('works with `Comparator.LT_OR_EQ`', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [{ field: 'foo', comparator: Comparator.LT_OR_EQ, value: 1 }] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ range: { foo: { lte: 1 } } }], + it('works with `Comparator.LT_OR_EQ`', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [{ field: 'foo', comparator: Comparator.LT_OR_EQ, value: 1 }] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + range: { + foo: { + lte: 1, + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); }); -}); -describe('Multiple criteria create the right ES query', () => { - beforeEach(() => { - services.callCluster.mockReset(); - }); - it('works', async () => { - await callExecutor( - [2, Comparator.GT, 1], // Not relevant - [ - { field: 'foo', comparator: Comparator.EQ, value: 'bar' }, - { field: 'http.status', comparator: Comparator.LT, value: 400 }, - ] - ); - - const query = services.callCluster.mock.calls[0][1]!; - expect(query.body).toMatchObject({ - query: { - bool: { - must: [{ term: { foo: { value: 'bar' } } }, { range: { 'http.status': { lt: 400 } } }], + describe('Multiple criteria create the right ES query', () => { + beforeEach(() => { + services.callCluster.mockReset(); + }); + it('works', async () => { + await callExecutor( + [2, Comparator.GT, 1], // Not relevant + [ + { field: 'foo', comparator: Comparator.EQ, value: 'bar' }, + { field: 'http.status', comparator: Comparator.LT, value: 400 }, + ] + ); + + const query = services.callCluster.mock.calls[0][1]!; + + expect(query.body).toMatchObject({ + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + format: 'epoch_millis', + }, + }, + }, + { + term: { + foo: { + value: 'bar', + }, + }, + }, + { + range: { + 'http.status': { + lt: 400, + }, + }, + }, + ], + }, }, - }, + size: 0, + }); }); }); }); diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index ee4e1fcb3f6e2a..a2fd01f8593852 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -11,10 +11,19 @@ import { Comparator, LogDocumentCountAlertParams, Criterion, + GroupedSearchQueryResponseRT, + UngroupedSearchQueryResponseRT, + UngroupedSearchQueryResponse, + GroupedSearchQueryResponse, + LogDocumentCountAlertParamsRT, } from '../../../../common/alerting/logs/types'; import { InfraBackendLibs } from '../../infra_types'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { InfraSource } from '../../../../common/http_api/source_api'; +import { decodeOrThrow } from '../../../../common/runtime_types'; + +const UNGROUPED_FACTORY_KEY = '*'; +const COMPOSITE_GROUP_SIZE = 40; const checkValueAgainstComparatorMap: { [key: string]: (a: number, b: number) => boolean; @@ -25,37 +34,42 @@ const checkValueAgainstComparatorMap: { [Comparator.LT_OR_EQ]: (a: number, b: number) => a <= b, }; -export const createLogThresholdExecutor = (alertUUID: string, libs: InfraBackendLibs) => +export const createLogThresholdExecutor = (alertId: string, libs: InfraBackendLibs) => async function ({ services, params }: AlertExecutorOptions) { - const { count, criteria } = params as LogDocumentCountAlertParams; const { alertInstanceFactory, savedObjectsClient, callCluster } = services; const { sources } = libs; + const { groupBy } = params; const sourceConfiguration = await sources.getSourceConfiguration(savedObjectsClient, 'default'); const indexPattern = sourceConfiguration.configuration.logAlias; - - const alertInstance = alertInstanceFactory(alertUUID); + const alertInstance = alertInstanceFactory(alertId); try { - const query = getESQuery( - params as LogDocumentCountAlertParams, - sourceConfiguration.configuration - ); - const result = await getResults(query, indexPattern, callCluster); - - if (checkValueAgainstComparatorMap[count.comparator](result.count, count.value)) { - alertInstance.scheduleActions(FIRED_ACTIONS.id, { - matchingDocuments: result.count, - conditions: createConditionsMessage(criteria), - }); - - alertInstance.replaceState({ - alertState: AlertStates.ALERT, - }); + const validatedParams = decodeOrThrow(LogDocumentCountAlertParamsRT)(params); + + const query = + groupBy && groupBy.length > 0 + ? getGroupedESQuery(validatedParams, sourceConfiguration.configuration, indexPattern) + : getUngroupedESQuery(validatedParams, sourceConfiguration.configuration, indexPattern); + + if (!query) { + throw new Error('ES query could not be built from the provided alert params'); + } + + if (groupBy && groupBy.length > 0) { + processGroupByResults( + await getGroupedResults(query, callCluster), + validatedParams, + alertInstanceFactory, + alertId + ); } else { - alertInstance.replaceState({ - alertState: AlertStates.OK, - }); + processUngroupedResults( + await getUngroupedResults(query, callCluster), + validatedParams, + alertInstanceFactory, + alertId + ); } } catch (e) { alertInstance.replaceState({ @@ -66,27 +80,82 @@ export const createLogThresholdExecutor = (alertUUID: string, libs: InfraBackend } }; -const getESQuery = ( +const processUngroupedResults = ( + results: UngroupedSearchQueryResponse, params: LogDocumentCountAlertParams, - sourceConfiguration: InfraSource['configuration'] -): object => { + alertInstanceFactory: AlertExecutorOptions['services']['alertInstanceFactory'], + alertId: string +) => { + const { count, criteria } = params; + + const alertInstance = alertInstanceFactory(`${alertId}-${UNGROUPED_FACTORY_KEY}`); + const documentCount = results.hits.total.value; + + if (checkValueAgainstComparatorMap[count.comparator](documentCount, count.value)) { + alertInstance.scheduleActions(FIRED_ACTIONS.id, { + matchingDocuments: documentCount, + conditions: createConditionsMessage(criteria), + group: null, + }); + + alertInstance.replaceState({ + alertState: AlertStates.ALERT, + }); + } else { + alertInstance.replaceState({ + alertState: AlertStates.OK, + }); + } +}; + +interface ReducedGroupByResults { + name: string; + documentCount: number; +} + +const processGroupByResults = ( + results: GroupedSearchQueryResponse['aggregations']['groups']['buckets'], + params: LogDocumentCountAlertParams, + alertInstanceFactory: AlertExecutorOptions['services']['alertInstanceFactory'], + alertId: string +) => { + const { count, criteria } = params; + + const groupResults = results.reduce((acc, groupBucket) => { + const groupName = Object.values(groupBucket.key).join(', '); + const groupResult = { name: groupName, documentCount: groupBucket.filtered_results.doc_count }; + return [...acc, groupResult]; + }, []); + + groupResults.forEach((group) => { + const alertInstance = alertInstanceFactory(`${alertId}-${group.name}`); + const documentCount = group.documentCount; + + if (checkValueAgainstComparatorMap[count.comparator](documentCount, count.value)) { + alertInstance.scheduleActions(FIRED_ACTIONS.id, { + matchingDocuments: documentCount, + conditions: createConditionsMessage(criteria), + group: group.name, + }); + + alertInstance.replaceState({ + alertState: AlertStates.ALERT, + }); + } else { + alertInstance.replaceState({ + alertState: AlertStates.OK, + }); + } + }); +}; + +const buildFiltersFromCriteria = (params: LogDocumentCountAlertParams, timestampField: string) => { const { timeSize, timeUnit, criteria } = params; const interval = `${timeSize}${timeUnit}`; const intervalAsSeconds = getIntervalInSeconds(interval); + const intervalAsMs = intervalAsSeconds * 1000; const to = Date.now(); - const from = to - intervalAsSeconds * 1000; - - const rangeFilters = [ - { - range: { - [sourceConfiguration.fields.timestamp]: { - gte: from, - lte: to, - format: 'epoch_millis', - }, - }, - }, - ]; + const from = to - intervalAsMs; const positiveComparators = getPositiveComparators(); const negativeComparators = getNegativeComparators(); @@ -101,17 +170,121 @@ const getESQuery = ( // Negative assertions (things that "must not" match) const mustNotFilters = buildFiltersForCriteria(negativeCriteria); - const query = { + const rangeFilter = { + range: { + [timestampField]: { + gte: from, + lte: to, + format: 'epoch_millis', + }, + }, + }; + + // For group by scenarios we'll pad the time range by 1 x the interval size on the left (lte) and right (gte), this is so + // a wider net is cast to "capture" the groups. This is to account for scenarios where we want ascertain if + // there were "no documents" (less than 1 for example). In these cases we may be missing documents to build the groups + // and match / not match the criteria. + const groupedRangeFilter = { + range: { + [timestampField]: { + gte: from - intervalAsMs, + lte: to + intervalAsMs, + format: 'epoch_millis', + }, + }, + }; + + return { rangeFilter, groupedRangeFilter, mustFilters, mustNotFilters }; +}; + +const getGroupedESQuery = ( + params: LogDocumentCountAlertParams, + sourceConfiguration: InfraSource['configuration'], + index: string +): object | undefined => { + const { groupBy } = params; + + if (!groupBy || !groupBy.length) { + return; + } + + const timestampField = sourceConfiguration.fields.timestamp; + + const { rangeFilter, groupedRangeFilter, mustFilters, mustNotFilters } = buildFiltersFromCriteria( + params, + timestampField + ); + + const aggregations = { + groups: { + composite: { + size: COMPOSITE_GROUP_SIZE, + sources: groupBy.map((field, groupIndex) => ({ + [`group-${groupIndex}-${field}`]: { + terms: { field }, + }, + })), + }, + aggregations: { + filtered_results: { + filter: { + bool: { + // Scope the inner filtering back to the unpadded range + filter: [rangeFilter, ...mustFilters], + }, + }, + }, + }, + }, + }; + + const body = { query: { bool: { - filter: [...rangeFilters], - ...(mustFilters.length > 0 && { must: mustFilters }), + filter: [groupedRangeFilter], ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), }, }, + aggregations, + size: 0, }; - return query; + return { + index, + allowNoIndices: true, + ignoreUnavailable: true, + body, + }; +}; + +const getUngroupedESQuery = ( + params: LogDocumentCountAlertParams, + sourceConfiguration: InfraSource['configuration'], + index: string +): object => { + const { rangeFilter, mustFilters, mustNotFilters } = buildFiltersFromCriteria( + params, + sourceConfiguration.fields.timestamp + ); + + const body = { + // Ensure we accurately track the hit count for the ungrouped case, otherwise we can only ensure accuracy up to 10,000. + track_total_hits: true, + query: { + bool: { + filter: [rangeFilter, ...mustFilters], + ...(mustNotFilters.length > 0 && { must_not: mustNotFilters }), + }, + }, + size: 0, + }; + + return { + index, + allowNoIndices: true, + ignoreUnavailable: true, + body, + }; }; type SupportedESQueryTypes = 'term' | 'match' | 'match_phrase' | 'range'; @@ -145,7 +318,6 @@ const buildCriterionQuery = (criterion: Criterion): Filter | undefined => { }, }, }; - break; case 'match': { return { match: { @@ -221,15 +393,31 @@ const getQueryMappingForComparator = (comparator: Comparator) => { return queryMappings[comparator]; }; -const getResults = async ( - query: object, - index: string, - callCluster: AlertServices['callCluster'] -) => { - return await callCluster('count', { - body: query, - index, - }); +const getUngroupedResults = async (query: object, callCluster: AlertServices['callCluster']) => { + return decodeOrThrow(UngroupedSearchQueryResponseRT)(await callCluster('search', query)); +}; + +const getGroupedResults = async (query: object, callCluster: AlertServices['callCluster']) => { + let compositeGroupBuckets: GroupedSearchQueryResponse['aggregations']['groups']['buckets'] = []; + let lastAfterKey: GroupedSearchQueryResponse['aggregations']['groups']['after_key'] | undefined; + + while (true) { + const queryWithAfterKey: any = { ...query }; + queryWithAfterKey.body.aggregations.groups.composite.after = lastAfterKey; + const groupResponse: GroupedSearchQueryResponse = decodeOrThrow(GroupedSearchQueryResponseRT)( + await callCluster('search', queryWithAfterKey) + ); + compositeGroupBuckets = [ + ...compositeGroupBuckets, + ...groupResponse.aggregations.groups.buckets, + ]; + lastAfterKey = groupResponse.aggregations.groups.after_key; + if (groupResponse.aggregations.groups.buckets.length < COMPOSITE_GROUP_SIZE) { + break; + } + } + + return compositeGroupBuckets; }; const createConditionsMessage = (criteria: LogDocumentCountAlertParams['criteria']) => { diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts index ed7e82fe29e4cd..43c298019b6325 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/register_log_threshold_alert_type.ts @@ -28,6 +28,13 @@ const conditionsActionVariableDescription = i18n.translate( } ); +const groupByActionVariableDescription = i18n.translate( + 'xpack.infra.logs.alerting.threshold.groupByActionVariableDescription', + { + defaultMessage: 'The name of the group responsible for triggering the alert', + } +); + const countSchema = schema.object({ value: schema.number(), comparator: schema.oneOf([ @@ -75,6 +82,7 @@ export async function registerLogThresholdAlertType( criteria: schema.arrayOf(criteriaSchema), timeUnit: schema.string(), timeSize: schema.number(), + groupBy: schema.maybe(schema.arrayOf(schema.string())), }), }, defaultActionGroupId: FIRED_ACTIONS.id, @@ -84,6 +92,7 @@ export async function registerLogThresholdAlertType( context: [ { name: 'matchingDocuments', description: documentCountActionVariableDescription }, { name: 'conditions', description: conditionsActionVariableDescription }, + { name: 'group', description: groupByActionVariableDescription }, ], }, producer: 'logs', From 06ee7bd2a3ac28872114db851fa7d6abd7f71e25 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Tue, 30 Jun 2020 12:14:21 +0200 Subject: [PATCH 02/13] [ML] Fix license subscription race condition. (#70074) Fixes a race condition where the ML plugin would be mounted before receiving its first license information update and thus redirecting to a fallback page (Kibana Home, Space-Chooser or Data Visualizer page depending on the setup). --- x-pack/plugins/ml/public/application/app.tsx | 6 +- .../application/license/check_license.tsx | 8 ++- .../license/ml_client_license.test.ts | 59 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/license/ml_client_license.test.ts diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 3df176ff25cb41..9539d530bab047 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -80,11 +80,11 @@ export const renderApp = ( deps.kibanaLegacy.loadFontAwesome(); - const mlLicense = setLicenseCache(deps.licensing); - appMountParams.onAppLeave((actions) => actions.default()); - ReactDOM.render(, appMountParams.element); + const mlLicense = setLicenseCache(deps.licensing, [ + () => ReactDOM.render(, appMountParams.element), + ]); return () => { mlLicense.unsubscribe(); diff --git a/x-pack/plugins/ml/public/application/license/check_license.tsx b/x-pack/plugins/ml/public/application/license/check_license.tsx index 3584ee8fbee4b6..583eec7d75414d 100644 --- a/x-pack/plugins/ml/public/application/license/check_license.tsx +++ b/x-pack/plugins/ml/public/application/license/check_license.tsx @@ -5,6 +5,7 @@ */ import { LicensingPluginSetup } from '../../../../licensing/public'; +import { MlLicense } from '../../../common/license'; import { MlClientLicense } from './ml_client_license'; let mlLicense: MlClientLicense | null = null; @@ -16,9 +17,12 @@ let mlLicense: MlClientLicense | null = null; * @param {LicensingPluginSetup} licensingSetup * @returns {MlClientLicense} */ -export function setLicenseCache(licensingSetup: LicensingPluginSetup) { +export function setLicenseCache( + licensingSetup: LicensingPluginSetup, + postInitFunctions?: Array<(lic: MlLicense) => void> +) { mlLicense = new MlClientLicense(); - mlLicense.setup(licensingSetup.license$); + mlLicense.setup(licensingSetup.license$, postInitFunctions); return mlLicense; } diff --git a/x-pack/plugins/ml/public/application/license/ml_client_license.test.ts b/x-pack/plugins/ml/public/application/license/ml_client_license.test.ts new file mode 100644 index 00000000000000..b37d7cfaa00aa8 --- /dev/null +++ b/x-pack/plugins/ml/public/application/license/ml_client_license.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Observable, Subject } from 'rxjs'; +import { ILicense } from '../../../../licensing/common/types'; + +import { MlClientLicense } from './ml_client_license'; + +describe('MlClientLicense', () => { + test('should miss the license update when initialized without postInitFunction', () => { + const mlLicense = new MlClientLicense(); + + // upon instantiation the full license doesn't get set + expect(mlLicense.isFullLicense()).toBe(false); + + const license$ = new Subject(); + + mlLicense.setup(license$ as Observable); + + // if the observable wasn't triggered the full license is still not set + expect(mlLicense.isFullLicense()).toBe(false); + + license$.next({ + check: () => ({ state: 'valid' }), + getFeature: () => ({ isEnabled: true }), + status: 'valid', + }); + + // once the observable triggered the license should be set + expect(mlLicense.isFullLicense()).toBe(true); + }); + + test('should not miss the license update when initialized with postInitFunction', (done) => { + const mlLicense = new MlClientLicense(); + + // upon instantiation the full license doesn't get set + expect(mlLicense.isFullLicense()).toBe(false); + + const license$ = new Subject(); + + mlLicense.setup(license$ as Observable, [ + (license) => { + // when passed in via postInitFunction callback, the license should be valid + // even if the license$ observable gets triggered after this setup. + expect(license.isFullLicense()).toBe(true); + done(); + }, + ]); + + license$.next({ + check: () => ({ state: 'valid' }), + getFeature: () => ({ isEnabled: true }), + status: 'valid', + }); + }); +}); From 351629f8e9f009e4e134d76c6b730f40d42c0f86 Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Tue, 30 Jun 2020 13:04:21 +0200 Subject: [PATCH 03/13] updates wording in Cases connectors (#70298) --- .../public/common/lib/connectors/jira/translations.ts | 2 +- .../public/common/lib/connectors/servicenow/translations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts index bcb2c49a0de74a..d7abf77a58d4ce 100644 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts +++ b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts @@ -11,7 +11,7 @@ export * from '../translations'; export const JIRA_DESC = i18n.translate( 'xpack.securitySolution.case.connectors.jira.selectMessageText', { - defaultMessage: 'Push or update SIEM case data to a new issue in Jira', + defaultMessage: 'Push or update Security case data to a new issue in Jira', } ); diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/servicenow/translations.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/servicenow/translations.ts index 0f06a4259e070e..b3e58dcd5b6be1 100644 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/servicenow/translations.ts +++ b/x-pack/plugins/security_solution/public/common/lib/connectors/servicenow/translations.ts @@ -11,7 +11,7 @@ export * from '../translations'; export const SERVICENOW_DESC = i18n.translate( 'xpack.securitySolution.case.connectors.servicenow.selectMessageText', { - defaultMessage: 'Push or update SIEM case data to a new incident in ServiceNow', + defaultMessage: 'Push or update Security case data to a new incident in ServiceNow', } ); From 7c352c0702d35f3e68451936dfc7c679dd67e8e1 Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Tue, 30 Jun 2020 12:38:12 +0100 Subject: [PATCH 04/13] [Dashboard] Add visualization by value to dashboard (#69898) * Plugging in DashboardStart dependency * Create embeddable by reference and navigate back to dashboard * Trying to feature flag the new flow * Feature flagging new visualize flow * Removing unnecessary console statement * Fixing typescript errors * Adding a functional test for new functionality * Adding a functional test for new functionality * Fixing test name * Changing test name * Moving functional test to a separate folder * Trying to fix the config file * Adding an index file * Remove falsly included file * Adding aggs and params to vis input * Serializing vis before passing it as an input * Incorporating new state transfer logic * Remove dashboardStart as a dependency * Trying to get the test to run * Remove unused import * Readding spaces * Fixing type errors * Incorporating new changes --- scripts/functional_tests.js | 1 + .../application/dashboard_app_controller.tsx | 13 +- .../visualize_embeddable_factory.tsx | 21 +- src/plugins/visualize/config.ts | 26 + .../visualize/public/application/types.ts | 2 + .../application/utils/get_top_nav_config.tsx | 22 +- src/plugins/visualize/public/plugin.ts | 5 + src/plugins/visualize/server/index.ts | 11 +- tasks/function_test_groups.js | 2 + .../services/dashboard/visualizations.ts | 26 + test/new_visualize_flow/config.js | 157 ++++++ .../new_visualize_flow/dashboard_embedding.js | 83 +++ .../fixtures/es_archiver/kibana/data.json.gz | Bin 0 -> 20860 bytes .../fixtures/es_archiver/kibana/mappings.json | 490 ++++++++++++++++++ test/new_visualize_flow/index.ts | 27 + 15 files changed, 870 insertions(+), 16 deletions(-) create mode 100644 src/plugins/visualize/config.ts create mode 100644 test/new_visualize_flow/config.js create mode 100644 test/new_visualize_flow/dashboard_embedding.js create mode 100644 test/new_visualize_flow/fixtures/es_archiver/kibana/data.json.gz create mode 100644 test/new_visualize_flow/fixtures/es_archiver/kibana/mappings.json create mode 100644 test/new_visualize_flow/index.ts diff --git a/scripts/functional_tests.js b/scripts/functional_tests.js index fc88f2657018f0..3fdab481dc7500 100644 --- a/scripts/functional_tests.js +++ b/scripts/functional_tests.js @@ -22,6 +22,7 @@ const alwaysImportedTests = [ require.resolve('../test/functional/config.js'), require.resolve('../test/plugin_functional/config.js'), require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'), + require.resolve('../test/new_visualize_flow/config.js'), ]; // eslint-disable-next-line no-restricted-syntax const onlyNotInCoverageTests = [ diff --git a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx index b52bf5bf02b7ba..58477d28f9081e 100644 --- a/src/plugins/dashboard/public/application/dashboard_app_controller.tsx +++ b/src/plugins/dashboard/public/application/dashboard_app_controller.tsx @@ -58,7 +58,6 @@ import { isErrorEmbeddable, openAddPanelFlyout, ViewMode, - SavedObjectEmbeddableInput, ContainerOutput, EmbeddableInput, } from '../../../embeddable/public'; @@ -432,14 +431,16 @@ export class DashboardAppController { .getIncomingEmbeddablePackage(); if (incomingState) { if ('id' in incomingState) { - container.addNewEmbeddable(incomingState.type, { + container.addNewEmbeddable(incomingState.type, { savedObjectId: incomingState.id, }); } else if ('input' in incomingState) { - container.addNewEmbeddable( - incomingState.type, - incomingState.input - ); + const input = incomingState.input; + delete input.id; + const explicitInput = { + savedVis: input, + }; + container.addNewEmbeddable(incomingState.type, explicitInput); } } } diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index eb4b66401820f1..b81ff5c1661831 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -30,7 +30,7 @@ import { import { DisabledLabEmbeddable } from './disabled_lab_embeddable'; import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualize_embeddable'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; -import { Vis } from '../vis'; +import { SerializedVis, Vis } from '../vis'; import { getCapabilities, getTypes, @@ -124,13 +124,20 @@ export class VisualizeEmbeddableFactory } } - public async create() { + public async create(input: VisualizeInput & { savedVis?: SerializedVis }, parent?: IContainer) { // TODO: This is a bit of a hack to preserve the original functionality. Ideally we will clean this up // to allow for in place creation of visualizations without having to navigate away to a new URL. - showNewVisModal({ - originatingApp: await this.getCurrentAppId(), - outsideVisualizeApp: true, - }); - return undefined; + if (input.savedVis) { + const visState = input.savedVis; + const vis = new Vis(visState.type, visState); + await vis.setState(visState); + return createVisEmbeddableFromObject(this.deps)(vis, input, parent); + } else { + showNewVisModal({ + originatingApp: await this.getCurrentAppId(), + outsideVisualizeApp: true, + }); + return undefined; + } } } diff --git a/src/plugins/visualize/config.ts b/src/plugins/visualize/config.ts new file mode 100644 index 00000000000000..ee79a37717f266 --- /dev/null +++ b/src/plugins/visualize/config.ts @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +export const configSchema = schema.object({ + showNewVisualizeFlow: schema.boolean({ defaultValue: false }), +}); + +export type ConfigSchema = TypeOf; diff --git a/src/plugins/visualize/public/application/types.ts b/src/plugins/visualize/public/application/types.ts index 20d55d1110f62b..a6adaf1f3c62b0 100644 --- a/src/plugins/visualize/public/application/types.ts +++ b/src/plugins/visualize/public/application/types.ts @@ -44,6 +44,7 @@ import { SharePluginStart } from 'src/plugins/share/public'; import { SavedObjectsStart, SavedObject } from 'src/plugins/saved_objects/public'; import { EmbeddableStart } from 'src/plugins/embeddable/public'; import { KibanaLegacyStart } from 'src/plugins/kibana_legacy/public'; +import { ConfigSchema } from '../../config'; export type PureVisState = SavedVisState; @@ -110,6 +111,7 @@ export interface VisualizeServices extends CoreStart { createVisEmbeddableFromObject: VisualizationsStart['__LEGACY']['createVisEmbeddableFromObject']; restorePreviousUrl: () => void; scopedHistory: ScopedHistory; + featureFlagConfig: ConfigSchema; } export interface SavedVisInstance { diff --git a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx index e04177fc619e2d..96f64c6478fa97 100644 --- a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { TopNavMenuData } from 'src/plugins/navigation/public'; +import uuid from 'uuid'; import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../visualizations/public'; import { showSaveModal, @@ -33,7 +34,6 @@ import { unhashUrl } from '../../../../kibana_utils/public'; import { SavedVisInstance, VisualizeServices, VisualizeAppStateContainer } from '../types'; import { VisualizeConstants } from '../visualize_constants'; import { getEditBreadcrumbs } from './breadcrumbs'; - interface TopNavConfigParams { hasUnsavedChanges: boolean; setHasUnsavedChanges: (value: boolean) => void; @@ -66,6 +66,7 @@ export const getTopNavConfig = ( toastNotifications, visualizeCapabilities, i18n: { Context: I18nContext }, + featureFlagConfig, }: VisualizeServices ) => { /** @@ -234,6 +235,19 @@ export const getTopNavConfig = ( return response; }; + const createVisReference = () => { + if (!originatingApp) { + return; + } + const input = { + ...vis.serialize(), + id: uuid.v4(), + }; + embeddable.getStateTransfer().navigateToWithEmbeddablePackage(originatingApp, { + state: { input, type: VISUALIZE_EMBEDDABLE_TYPE }, + }); + }; + const saveModal = ( ); - showSaveModal(saveModal, I18nContext); + if (originatingApp === 'dashboards' && featureFlagConfig.showNewVisualizeFlow) { + createVisReference(); + } else { + showSaveModal(saveModal, I18nContext); + } }, }, ] diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 5be560f7fb6323..fd9a67599414f1 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -60,6 +60,10 @@ export interface VisualizePluginSetupDependencies { data: DataPublicPluginSetup; } +export interface FeatureFlagConfig { + showNewVisualizeFlow: boolean; +} + export class VisualizePlugin implements Plugin { @@ -165,6 +169,7 @@ export class VisualizePlugin savedObjectsPublic: pluginsStart.savedObjects, scopedHistory: params.history, restorePreviousUrl, + featureFlagConfig: this.initializerContext.config.get(), }; params.element.classList.add('visAppWrapper'); diff --git a/src/plugins/visualize/server/index.ts b/src/plugins/visualize/server/index.ts index 5cebef71d8d22e..6da0a513b1475d 100644 --- a/src/plugins/visualize/server/index.ts +++ b/src/plugins/visualize/server/index.ts @@ -17,8 +17,17 @@ * under the License. */ -import { PluginInitializerContext } from 'kibana/server'; +import { PluginInitializerContext, PluginConfigDescriptor } from 'kibana/server'; import { VisualizeServerPlugin } from './plugin'; +import { ConfigSchema, configSchema } from '../config'; + +export const config: PluginConfigDescriptor = { + exposeToBrowser: { + showNewVisualizeFlow: true, + }, + schema: configSchema, +}; + export const plugin = (initContext: PluginInitializerContext) => new VisualizeServerPlugin(initContext); diff --git a/tasks/function_test_groups.js b/tasks/function_test_groups.js index 799b9e9eb81947..d60f3ae53eecc3 100644 --- a/tasks/function_test_groups.js +++ b/tasks/function_test_groups.js @@ -41,6 +41,8 @@ const getDefaultArgs = (tag) => { // '--config', 'test/functional/config.firefox.js', '--bail', '--debug', + '--config', + 'test/new_visualize_flow/config.js', ]; }; diff --git a/test/functional/services/dashboard/visualizations.ts b/test/functional/services/dashboard/visualizations.ts index 10747658d8c9b7..a5c16010d3ebaa 100644 --- a/test/functional/services/dashboard/visualizations.ts +++ b/test/functional/services/dashboard/visualizations.ts @@ -139,5 +139,31 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F redirectToOrigin: true, }); } + + async createAndEmbedMetric(name: string) { + log.debug(`createAndEmbedMetric(${name})`); + const inViewMode = await PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await PageObjects.dashboard.switchToEditMode(); + } + await this.ensureNewVisualizationDialogIsShowing(); + await PageObjects.visualize.clickMetric(); + await find.clickByCssSelector('li.euiListGroupItem:nth-of-type(2)'); + await testSubjects.exists('visualizeSaveButton'); + await testSubjects.click('visualizeSaveButton'); + } + + async createAndEmbedMarkdown({ name, markdown }: { name: string; markdown: string }) { + log.debug(`createAndEmbedMarkdown(${markdown})`); + const inViewMode = await PageObjects.dashboard.getIsInViewMode(); + if (inViewMode) { + await PageObjects.dashboard.switchToEditMode(); + } + await this.ensureNewVisualizationDialogIsShowing(); + await PageObjects.visualize.clickMarkdownWidget(); + await PageObjects.visEditor.setMarkdownTxt(markdown); + await PageObjects.visEditor.clickGo(); + await testSubjects.click('visualizeSaveButton'); + } })(); } diff --git a/test/new_visualize_flow/config.js b/test/new_visualize_flow/config.js new file mode 100644 index 00000000000000..a6440d16481d59 --- /dev/null +++ b/test/new_visualize_flow/config.js @@ -0,0 +1,157 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { pageObjects } from '../functional/page_objects'; +import { services } from '../functional/services'; + +export default async function ({ readConfigFile }) { + const commonConfig = await readConfigFile(require.resolve('../functional/config.js')); + + return { + testFiles: [require.resolve('./dashboard_embedding')], + pageObjects, + services, + servers: commonConfig.get('servers'), + + esTestCluster: commonConfig.get('esTestCluster'), + + kbnTestServer: { + ...commonConfig.get('kbnTestServer'), + serverArgs: [ + ...commonConfig.get('kbnTestServer.serverArgs'), + '--oss', + '--telemetry.optIn=false', + '--visualize.showNewVisualizeFlow=true', + ], + }, + + uiSettings: { + defaults: { + 'accessibility:disableAnimations': true, + 'dateFormat:tz': 'UTC', + }, + }, + + apps: { + kibana: { + pathname: '/app/kibana', + }, + status_page: { + pathname: '/status', + }, + discover: { + pathname: '/app/discover', + hash: '/', + }, + context: { + pathname: '/app/discover', + hash: '/context', + }, + visualize: { + pathname: '/app/visualize', + hash: '/', + }, + dashboard: { + pathname: '/app/dashboards', + hash: '/list', + }, + management: { + pathname: '/app/management', + }, + console: { + pathname: '/app/dev_tools', + hash: '/console', + }, + home: { + pathname: '/app/home', + hash: '/', + }, + }, + junit: { + reportName: 'Chrome UI Functional Tests', + }, + browser: { + type: 'chrome', + }, + + security: { + roles: { + test_logstash_reader: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['logstash*'], + privileges: ['read', 'view_index_metadata'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + //for sample data - can remove but not add sample data + kibana_sample_admin: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['kibana_sample*'], + privileges: ['read', 'view_index_metadata', 'manage', 'create_index', 'index'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + long_window_logstash: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['long-window-logstash-*'], + privileges: ['read', 'view_index_metadata'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + + animals: { + elasticsearch: { + cluster: [], + indices: [ + { + names: ['animals-*'], + privileges: ['read', 'view_index_metadata'], + field_security: { grant: ['*'], except: [] }, + }, + ], + run_as: [], + }, + kibana: [], + }, + }, + defaultRoles: ['kibana_admin'], + }, + }; +} diff --git a/test/new_visualize_flow/dashboard_embedding.js b/test/new_visualize_flow/dashboard_embedding.js new file mode 100644 index 00000000000000..b1a6bd14547fbd --- /dev/null +++ b/test/new_visualize_flow/dashboard_embedding.js @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; + +/** + * This tests both that one of each visualization can be added to a dashboard (as opposed to opening an existing + * dashboard with the visualizations already on it), as well as conducts a rough type of snapshot testing by checking + * for various ui components. The downside is these tests are a bit fragile to css changes (though not as fragile as + * actual screenshot snapshot regression testing), and can be difficult to diagnose failures (which visualization + * broke?). The upside is that this offers very good coverage with a minimal time investment. + */ + +export default function ({ getService, getPageObjects }) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const dashboardExpect = getService('dashboardExpect'); + const testSubjects = getService('testSubjects'); + const dashboardVisualizations = getService('dashboardVisualizations'); + const PageObjects = getPageObjects([ + 'common', + 'dashboard', + 'header', + 'visualize', + 'discover', + 'timePicker', + ]); + + describe('Dashboard Embedding', function describeIndexTests() { + before(async () => { + await esArchiver.load('kibana'); + await kibanaServer.uiSettings.replace({ + defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', + }); + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.preserveCrossAppState(); + await PageObjects.dashboard.clickNewDashboard(); + }); + + it('adding a metric visualization', async function () { + const originalPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(originalPanelCount).to.eql(0); + await testSubjects.exists('addVisualizationButton'); + await testSubjects.click('addVisualizationButton'); + await dashboardVisualizations.createAndEmbedMetric('Embedding Vis Test'); + await PageObjects.dashboard.waitForRenderComplete(); + await dashboardExpect.metricValuesExist(['0']); + const panelCount = await PageObjects.dashboard.getPanelCount(); + expect(panelCount).to.eql(1); + }); + + it('adding a markdown', async function () { + const originalPanelCount = await PageObjects.dashboard.getPanelCount(); + expect(originalPanelCount).to.eql(1); + await testSubjects.exists('dashboardAddNewPanelButton'); + await testSubjects.click('dashboardAddNewPanelButton'); + await dashboardVisualizations.createAndEmbedMarkdown({ + name: 'Embedding Markdown Test', + markdown: 'Nice to meet you, markdown is my name', + }); + await PageObjects.dashboard.waitForRenderComplete(); + await dashboardExpect.markdownWithValuesExists(['Nice to meet you, markdown is my name']); + const panelCount = await PageObjects.dashboard.getPanelCount(); + expect(panelCount).to.eql(2); + }); + }); +} diff --git a/test/new_visualize_flow/fixtures/es_archiver/kibana/data.json.gz b/test/new_visualize_flow/fixtures/es_archiver/kibana/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..ae78761fef0d3415c8ec05ea4bfa9dcca070981a GIT binary patch literal 20860 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 literal 0 HcmV?d00001 diff --git a/test/new_visualize_flow/fixtures/es_archiver/kibana/mappings.json b/test/new_visualize_flow/fixtures/es_archiver/kibana/mappings.json new file mode 100644 index 00000000000000..9f5edaad0fe763 --- /dev/null +++ b/test/new_visualize_flow/fixtures/es_archiver/kibana/mappings.json @@ -0,0 +1,490 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana": { + } + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1", + "application_usage_transactional": "965839e75f809fefe04f92dc4d99722a", + "config": "ae24d22d5986d04124cc6568f771066f", + "dashboard": "d00f614b29a80360e1190193fd333bab", + "index-pattern": "66eccb05066c5a89924f48a9e9736499", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "181661168bbadd1eff5902361e2a0d5c", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", + "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "url": "b675c3be8d76ecf029294d51dc7ec65d", + "visualization": "52d7a13ad68a150c4525b292d23e12cc" + } + }, + "dynamic": "strict", + "properties": { + "application_usage_totals": { + "properties": { + "appId": { + "type": "keyword" + }, + "minutesOnScreen": { + "type": "float" + }, + "numberOfClicks": { + "type": "long" + } + } + }, + "application_usage_transactional": { + "properties": { + "appId": { + "type": "keyword" + }, + "minutesOnScreen": { + "type": "float" + }, + "numberOfClicks": { + "type": "long" + }, + "timestamp": { + "type": "date" + } + } + }, + "config": { + "dynamic": "true", + "properties": { + "accessibility:disableAnimations": { + "type": "boolean" + }, + "buildNum": { + "type": "keyword" + }, + "dateFormat:tz": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "defaultIndex": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "notifications:lifetime:banner": { + "type": "long" + }, + "notifications:lifetime:error": { + "type": "long" + }, + "notifications:lifetime:info": { + "type": "long" + }, + "notifications:lifetime:warning": { + "type": "long" + }, + "xPackMonitoring:showBanner": { + "type": "boolean" + } + } + }, + "dashboard": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "optionsJSON": { + "type": "text" + }, + "panelsJSON": { + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "type": "keyword" + }, + "pause": { + "type": "boolean" + }, + "section": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "timeFrom": { + "type": "keyword" + }, + "timeRestore": { + "type": "boolean" + }, + "timeTo": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "index-pattern": { + "properties": { + "fieldFormatMap": { + "type": "text" + }, + "fields": { + "type": "text" + }, + "intervalName": { + "type": "keyword" + }, + "notExpandable": { + "type": "boolean" + }, + "sourceFilters": { + "type": "text" + }, + "timeFieldName": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "type": { + "type": "keyword" + }, + "typeMeta": { + "type": "keyword" + } + } + }, + "kql-telemetry": { + "properties": { + "optInCount": { + "type": "long" + }, + "optOutCount": { + "type": "long" + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "dashboard": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "index-pattern": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "search": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "visualization": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "sample-data-telemetry": { + "properties": { + "installCount": { + "type": "long" + }, + "unInstallCount": { + "type": "long" + } + } + }, + "search": { + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "server": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "telemetry": { + "properties": { + "allowChangingOptInStatus": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "lastReported": { + "type": "date" + }, + "lastVersionChecked": { + "type": "keyword" + }, + "reportFailureCount": { + "type": "integer" + }, + "reportFailureVersion": { + "type": "keyword" + }, + "sendUsageFrom": { + "type": "keyword" + }, + "userHasSeenNotice": { + "type": "boolean" + } + } + }, + "timelion-sheet": { + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "tsvb-validation-telemetry": { + "properties": { + "failedRequests": { + "type": "long" + } + } + }, + "type": { + "type": "keyword" + }, + "ui-metric": { + "properties": { + "count": { + "type": "integer" + } + } + }, + "updated_at": { + "type": "date" + }, + "url": { + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "visualization": { + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "savedSearchRefName": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "type": "text" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} \ No newline at end of file diff --git a/test/new_visualize_flow/index.ts b/test/new_visualize_flow/index.ts new file mode 100644 index 00000000000000..e915525155990e --- /dev/null +++ b/test/new_visualize_flow/index.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { FtrProviderContext } from '../functional/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ loadTestFile }: FtrProviderContext) { + describe('New Visualize Flow', function () { + this.tags('ciGroup2'); + loadTestFile(require.resolve('./dashboard_embedding')); + }); +} From 6027451687ed5697cab48bc3dff30ca391193fa4 Mon Sep 17 00:00:00 2001 From: Dmitry Lemeshko Date: Tue, 30 Jun 2020 15:27:39 +0200 Subject: [PATCH 05/13] [code coverage] ingest correct coveredFilePath for mocha (#70215) * [code coverage] ingest correct coveredFilePath for mocha * export variable globally so it is availble in node script --- src/dev/code_coverage/shell_scripts/ingest_coverage.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dev/code_coverage/shell_scripts/ingest_coverage.sh b/src/dev/code_coverage/shell_scripts/ingest_coverage.sh index b7064a1e426717..2dae75484d68fc 100644 --- a/src/dev/code_coverage/shell_scripts/ingest_coverage.sh +++ b/src/dev/code_coverage/shell_scripts/ingest_coverage.sh @@ -17,7 +17,7 @@ export ES_HOST STATIC_SITE_URL_BASE='https://kibana-coverage.elastic.dev' export STATIC_SITE_URL_BASE -for x in jest functional mocha; do +for x in jest functional; do echo "### Ingesting coverage for ${x}" COVERAGE_SUMMARY_FILE=target/kibana-coverage/${x}-combined/coverage-summary.json @@ -25,5 +25,11 @@ for x in jest functional mocha; do node scripts/ingest_coverage.js --verbose --path ${COVERAGE_SUMMARY_FILE} --vcsInfoPath ./VCS_INFO.txt done +# Need to override COVERAGE_INGESTION_KIBANA_ROOT since mocha json file has original intake worker path +COVERAGE_SUMMARY_FILE=target/kibana-coverage/mocha-combined/coverage-summary.json +export COVERAGE_INGESTION_KIBANA_ROOT=/dev/shm/workspace/kibana + +node scripts/ingest_coverage.js --verbose --path ${COVERAGE_SUMMARY_FILE} --vcsInfoPath ./VCS_INFO.txt + echo "### Ingesting Code Coverage - Complete" echo "" From 82fd107fc2df3e38c4c9d5f906826cba3f4de468 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 30 Jun 2020 15:55:15 +0200 Subject: [PATCH 06/13] Fix typo in bootstrap command (#69976) --- packages/kbn-pm/dist/index.js | 2 +- packages/kbn-pm/src/commands/bootstrap.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 69611ed3f5c5e2..b8794124ad197d 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -8868,7 +8868,7 @@ const BootstrapCommand = { } if (cachedProjectCount > 0) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`${cachedProjectCount} bootsrap builds are cached`); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`${cachedProjectCount} bootstrap builds are cached`); } await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async project => { diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts index f8e50a8247856e..a559f9a20432a8 100644 --- a/packages/kbn-pm/src/commands/bootstrap.ts +++ b/packages/kbn-pm/src/commands/bootstrap.ts @@ -82,7 +82,7 @@ export const BootstrapCommand: ICommand = { } if (cachedProjectCount > 0) { - log.success(`${cachedProjectCount} bootsrap builds are cached`); + log.success(`${cachedProjectCount} bootstrap builds are cached`); } await parallelizeBatches(batchedProjects, async (project) => { From 3caab366c7000a498d9e26c9c5dad2f248314ff8 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Tue, 30 Jun 2020 08:04:48 -0600 Subject: [PATCH 07/13] [Maps] Add maps telemetry saved object in with mappings disabled (#69995) Co-authored-by: Rudolf Meijering Co-authored-by: Elastic Machine --- x-pack/plugins/maps/server/plugin.ts | 3 ++- .../maps/server/saved_objects/index.ts | 1 + .../server/saved_objects/maps_telemetry.ts | 23 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/maps/server/saved_objects/maps_telemetry.ts diff --git a/x-pack/plugins/maps/server/plugin.ts b/x-pack/plugins/maps/server/plugin.ts index 60f3a9b68202c8..dbcce50ac2b9af 100644 --- a/x-pack/plugins/maps/server/plugin.ts +++ b/x-pack/plugins/maps/server/plugin.ts @@ -15,7 +15,7 @@ import { getFlightsSavedObjects } from './sample_data/flights_saved_objects.js'; import { getWebLogsSavedObjects } from './sample_data/web_logs_saved_objects.js'; import { registerMapsUsageCollector } from './maps_telemetry/collectors/register'; import { APP_ID, APP_ICON, MAP_SAVED_OBJECT_TYPE, getExistingMapPath } from '../common/constants'; -import { mapSavedObjects } from './saved_objects'; +import { mapSavedObjects, mapsTelemetrySavedObjects } from './saved_objects'; import { MapsXPackConfig } from '../config'; // @ts-ignore import { setInternalRepository } from './kibana_server_services'; @@ -191,6 +191,7 @@ export class MapsPlugin implements Plugin { }, }); + core.savedObjects.registerType(mapsTelemetrySavedObjects); core.savedObjects.registerType(mapSavedObjects); registerMapsUsageCollector(usageCollection, currentConfig); diff --git a/x-pack/plugins/maps/server/saved_objects/index.ts b/x-pack/plugins/maps/server/saved_objects/index.ts index 804d720a13ab05..c4b779183a2dee 100644 --- a/x-pack/plugins/maps/server/saved_objects/index.ts +++ b/x-pack/plugins/maps/server/saved_objects/index.ts @@ -3,4 +3,5 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +export { mapsTelemetrySavedObjects } from './maps_telemetry'; export { mapSavedObjects } from './map'; diff --git a/x-pack/plugins/maps/server/saved_objects/maps_telemetry.ts b/x-pack/plugins/maps/server/saved_objects/maps_telemetry.ts new file mode 100644 index 00000000000000..c0d36983f65cdb --- /dev/null +++ b/x-pack/plugins/maps/server/saved_objects/maps_telemetry.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SavedObjectsType } from 'src/core/server'; + +/* + * The maps-telemetry saved object type isn't used, but in order to remove these fields from + * the mappings we register this type with `type: 'object', enabled: true` to remove all + * previous fields from the mappings until https://github.com/elastic/kibana/issues/67086 is + * solved. + */ +export const mapsTelemetrySavedObjects: SavedObjectsType = { + name: 'maps-telemetry', + hidden: false, + namespaceType: 'agnostic', + mappings: { + // @ts-ignore Core types don't support this since it's only really valid when removing a previously registered type + type: 'object', + enabled: false, + }, +}; From 233d261674799668d0938ee033c8632e377cebc0 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Tue, 30 Jun 2020 10:07:50 -0400 Subject: [PATCH 08/13] [ML] Anomaly Detection: ensure 'Category examples' tab in the expanded table row can be seen (#70241) * remove space from tab id * update test --- .../application/components/anomalies_table/anomaly_details.js | 2 +- .../components/anomalies_table/anomaly_details.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js index edc1790b3adac7..7b979d74a329cb 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.js @@ -279,7 +279,7 @@ export class AnomalyDetails extends Component { ), }, { - id: 'Category examples', + id: 'category-examples', name: i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.categoryExamplesTitle', { defaultMessage: 'Category examples', }), diff --git a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js index 9fd1ffc3b637fa..78c036eac19038 100644 --- a/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js +++ b/x-pack/plugins/ml/public/application/components/anomalies_table/anomaly_details.test.js @@ -67,7 +67,7 @@ describe('AnomalyDetails', () => { tabIndex: 1, }; const wrapper = shallowWithIntl(); - expect(wrapper.prop('initialSelectedTab').id).toBe('Category examples'); + expect(wrapper.prop('initialSelectedTab').id).toBe('category-examples'); }); test('Renders with terms and regex when definition prop is not undefined', () => { From ad01223c5acba50ee71771a2330ac95a370c651e Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Tue, 30 Jun 2020 16:13:28 +0200 Subject: [PATCH 09/13] chore: improve support for mjs file extension (#70186) --- .eslintrc.js | 56 +++++++++---------- .../core/development-unit-tests.asciidoc | 2 +- packages/eslint-config-kibana/jest.js | 4 +- src/dev/jest/config.js | 4 +- src/dev/run_eslint.js | 2 +- x-pack/dev-tools/jest/create_jest_config.js | 12 ++-- x-pack/plugins/apm/jest.config.js | 6 +- x-pack/test_utils/jest/config.integration.js | 4 +- x-pack/test_utils/jest/config.js | 4 +- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 32f59c4d6b3db5..2c49bf78c67b16 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -64,63 +64,63 @@ module.exports = { * Temporarily disable some react rules for specific plugins, remove in separate PRs */ { - files: ['packages/kbn-ui-framework/**/*.{js,ts,tsx}'], + files: ['packages/kbn-ui-framework/**/*.{js,mjs,ts,tsx}'], rules: { 'jsx-a11y/no-onchange': 'off', }, }, { - files: ['src/plugins/es_ui_shared/**/*.{js,ts,tsx}'], + files: ['src/plugins/es_ui_shared/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, }, { - files: ['src/plugins/kibana_react/**/*.{js,ts,tsx}'], + files: ['src/plugins/kibana_react/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/rules-of-hooks': 'off', 'react-hooks/exhaustive-deps': 'off', }, }, { - files: ['src/plugins/kibana_utils/**/*.{js,ts,tsx}'], + files: ['src/plugins/kibana_utils/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, }, { - files: ['x-pack/plugins/canvas/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/canvas/**/*.{js,mjs,ts,tsx}'], rules: { 'jsx-a11y/click-events-have-key-events': 'off', }, }, { - files: ['x-pack/plugins/cross_cluster_replication/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/cross_cluster_replication/**/*.{js,mjs,ts,tsx}'], rules: { 'jsx-a11y/click-events-have-key-events': 'off', }, }, { - files: ['x-pack/legacy/plugins/index_management/**/*.{js,ts,tsx}'], + files: ['x-pack/legacy/plugins/index_management/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', 'react-hooks/rules-of-hooks': 'off', }, }, { - files: ['x-pack/plugins/lens/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/lens/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, }, { - files: ['x-pack/plugins/ml/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/ml/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, }, { - files: ['x-pack/legacy/plugins/snapshot_restore/**/*.{js,ts,tsx}'], + files: ['x-pack/legacy/plugins/snapshot_restore/**/*.{js,mjs,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, @@ -132,7 +132,7 @@ module.exports = { * Licence headers */ { - files: ['**/*.{js,ts,tsx}', '!plugins/**/*'], + files: ['**/*.{js,mjs,ts,tsx}', '!plugins/**/*'], rules: { '@kbn/eslint/require-license-header': [ 'error', @@ -153,7 +153,7 @@ module.exports = { * New Platform client-side */ { - files: ['{src,x-pack}/plugins/*/public/**/*.{js,ts,tsx}'], + files: ['{src,x-pack}/plugins/*/public/**/*.{js,mjs,ts,tsx}'], rules: { 'import/no-commonjs': 'error', }, @@ -163,7 +163,7 @@ module.exports = { * Files that require Elastic license headers instead of Apache 2.0 header */ { - files: ['x-pack/**/*.{js,ts,tsx}'], + files: ['x-pack/**/*.{js,mjs,ts,tsx}'], rules: { '@kbn/eslint/require-license-header': [ 'error', @@ -184,7 +184,7 @@ module.exports = { * Restricted paths */ { - files: ['**/*.{js,ts,tsx}'], + files: ['**/*.{js,mjs,ts,tsx}'], rules: { '@kbn/eslint/no-restricted-paths': [ 'error', @@ -251,8 +251,8 @@ module.exports = { ], from: [ '(src|x-pack)/plugins/**/(public|server)/**/*', - '!(src|x-pack)/plugins/**/(public|server)/mocks/index.{js,ts}', - '!(src|x-pack)/plugins/**/(public|server)/(index|mocks).{js,ts,tsx}', + '!(src|x-pack)/plugins/**/(public|server)/mocks/index.{js,mjs,ts}', + '!(src|x-pack)/plugins/**/(public|server)/(index|mocks).{js,mjs,ts,tsx}', ], allowSameFolder: true, errorMessage: 'Plugins may only import from top-level public and server modules.', @@ -264,11 +264,11 @@ module.exports = { 'src/legacy/core_plugins/**/*', '!src/legacy/core_plugins/**/server/**/*', - '!src/legacy/core_plugins/**/index.{js,ts,tsx}', + '!src/legacy/core_plugins/**/index.{js,mjs,ts,tsx}', 'x-pack/legacy/plugins/**/*', '!x-pack/legacy/plugins/**/server/**/*', - '!x-pack/legacy/plugins/**/index.{js,ts,tsx}', + '!x-pack/legacy/plugins/**/index.{js,mjs,ts,tsx}', 'examples/**/*', '!examples/**/server/**/*', @@ -530,7 +530,7 @@ module.exports = { * Jest specific rules */ { - files: ['**/*.test.{js,ts,tsx}'], + files: ['**/*.test.{js,mjs,ts,tsx}'], rules: { 'jest/valid-describe': 'error', }, @@ -595,8 +595,8 @@ module.exports = { { // front end and common typescript and javascript files only files: [ - 'x-pack/plugins/security_solution/public/**/*.{js,ts,tsx}', - 'x-pack/plugins/security_solution/common/**/*.{js,ts,tsx}', + 'x-pack/plugins/security_solution/public/**/*.{js,mjs,ts,tsx}', + 'x-pack/plugins/security_solution/common/**/*.{js,mjs,ts,tsx}', ], rules: { 'import/no-nodejs-modules': 'error', @@ -646,7 +646,7 @@ module.exports = { // { // // will introduced after the other warns are fixed // // typescript and javascript for front end react performance - // files: ['x-pack/plugins/security_solution/public/**/!(*.test).{js,ts,tsx}'], + // files: ['x-pack/plugins/security_solution/public/**/!(*.test).{js,mjs,ts,tsx}'], // plugins: ['react-perf'], // rules: { // // 'react-perf/jsx-no-new-object-as-prop': 'error', @@ -657,7 +657,7 @@ module.exports = { // }, { // typescript and javascript for front and back end - files: ['x-pack/{,legacy/}plugins/security_solution/**/*.{js,ts,tsx}'], + files: ['x-pack/{,legacy/}plugins/security_solution/**/*.{js,mjs,ts,tsx}'], plugins: ['eslint-plugin-node', 'react'], env: { mocha: true, @@ -776,8 +776,8 @@ module.exports = { { // front end and common typescript and javascript files only files: [ - 'x-pack/plugins/lists/public/**/*.{js,ts,tsx}', - 'x-pack/plugins/lists/common/**/*.{js,ts,tsx}', + 'x-pack/plugins/lists/public/**/*.{js,mjs,ts,tsx}', + 'x-pack/plugins/lists/common/**/*.{js,mjs,ts,tsx}', ], rules: { 'import/no-nodejs-modules': 'error', @@ -792,7 +792,7 @@ module.exports = { }, { // typescript and javascript for front and back end - files: ['x-pack/plugins/lists/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/lists/**/*.{js,mjs,ts,tsx}'], plugins: ['eslint-plugin-node'], env: { mocha: true, @@ -1020,8 +1020,8 @@ module.exports = { */ { files: [ - 'src/plugins/vis_type_timeseries/**/*.{js,ts,tsx}', - 'src/legacy/core_plugins/vis_type_timeseries/**/*.{js,ts,tsx}', + 'src/plugins/vis_type_timeseries/**/*.{js,mjs,ts,tsx}', + 'src/legacy/core_plugins/vis_type_timeseries/**/*.{js,mjs,ts,tsx}', ], rules: { 'import/no-default-export': 'error', diff --git a/docs/developer/core/development-unit-tests.asciidoc b/docs/developer/core/development-unit-tests.asciidoc index a738e2cf372d97..04cce0dfec901d 100644 --- a/docs/developer/core/development-unit-tests.asciidoc +++ b/docs/developer/core/development-unit-tests.asciidoc @@ -22,7 +22,7 @@ yarn test:mocha [float] ==== Jest -Jest tests are stored in the same directory as source code files with the `.test.{js,ts,tsx}` suffix. +Jest tests are stored in the same directory as source code files with the `.test.{js,mjs,ts,tsx}` suffix. *Running Jest Unit Tests* diff --git a/packages/eslint-config-kibana/jest.js b/packages/eslint-config-kibana/jest.js index d682277ff905a4..c374de7ae123ca 100644 --- a/packages/eslint-config-kibana/jest.js +++ b/packages/eslint-config-kibana/jest.js @@ -2,8 +2,8 @@ module.exports = { overrides: [ { files: [ - '**/*.{test,test.mocks,mock}.{js,ts,tsx}', - '**/__mocks__/**/*.{js,ts,tsx}', + '**/*.{test,test.mocks,mock}.{js,mjs,ts,tsx}', + '**/__mocks__/**/*.{js,mjs,ts,tsx}', ], plugins: [ 'jest', diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index da343aa0f0672d..391a52b7f0397b 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -50,7 +50,7 @@ export default { 'packages/kbn-ui-framework/src/services/**/*.js', '!packages/kbn-ui-framework/src/services/index.js', '!packages/kbn-ui-framework/src/services/**/*/index.js', - 'src/legacy/core_plugins/**/*.{js,jsx,ts,tsx}', + 'src/legacy/core_plugins/**/*.{js,mjs,jsx,ts,tsx}', '!src/legacy/core_plugins/**/{__test__,__snapshots__}/**/*', '!src/legacy/core_plugins/tests_bundle/**', ], @@ -81,7 +81,7 @@ export default { ], coverageDirectory: '/target/kibana-coverage/jest', coverageReporters: !!process.env.CODE_COVERAGE ? ['json'] : ['html', 'text'], - moduleFileExtensions: ['js', 'json', 'ts', 'tsx', 'node'], + moduleFileExtensions: ['js', 'mjs', 'json', 'ts', 'tsx', 'node'], modulePathIgnorePatterns: ['__fixtures__/', 'target/'], testEnvironment: 'jest-environment-jsdom-thirteen', testMatch: ['**/*.test.{js,ts,tsx}'], diff --git a/src/dev/run_eslint.js b/src/dev/run_eslint.js index 3bfbb9cc876e06..3214a2fb454711 100644 --- a/src/dev/run_eslint.js +++ b/src/dev/run_eslint.js @@ -31,7 +31,7 @@ if (!process.argv.includes('--no-cache')) { } if (!process.argv.includes('--ext')) { - process.argv.push('--ext', '.js,.ts,.tsx'); + process.argv.push('--ext', '.js,.mjs,.ts,.tsx'); } // common-js is required so that logic before this executes before loading eslint diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js index 9b6db8b74458b5..a0574dbdf36da6 100644 --- a/x-pack/dev-tools/jest/create_jest_config.js +++ b/x-pack/dev-tools/jest/create_jest_config.js @@ -9,7 +9,7 @@ export function createJestConfig({ kibanaDirectory, rootDir, xPackKibanaDirector return { rootDir, roots: ['/plugins', '/legacy/plugins', '/legacy/server'], - moduleFileExtensions: ['js', 'json', 'ts', 'tsx', 'node'], + moduleFileExtensions: ['js', 'mjs', 'json', 'ts', 'tsx', 'node'], moduleNameMapper: { '@elastic/eui$': `${kibanaDirectory}/node_modules/@elastic/eui/test-env`, '@elastic/eui/lib/(.*)?': `${kibanaDirectory}/node_modules/@elastic/eui/test-env/$1`, @@ -32,11 +32,11 @@ export function createJestConfig({ kibanaDirectory, rootDir, xPackKibanaDirector '^(!!)?file-loader!': fileMockPath, }, collectCoverageFrom: [ - 'legacy/plugins/**/*.{js,jsx,ts,tsx}', - 'legacy/server/**/*.{js,jsx,ts,tsx}', - 'plugins/**/*.{js,jsx,ts,tsx}', + 'legacy/plugins/**/*.{js,mjs,jsx,ts,tsx}', + 'legacy/server/**/*.{js,mjs,jsx,ts,tsx}', + 'plugins/**/*.{js,mjs,jsx,ts,tsx}', '!**/{__test__,__snapshots__,__examples__,integration_tests,tests}/**', - '!**/*.test.{js,ts,tsx}', + '!**/*.test.{js,mjs,ts,tsx}', '!**/flot-charts/**', '!**/test/**', '!**/build/**', @@ -60,7 +60,7 @@ export function createJestConfig({ kibanaDirectory, rootDir, xPackKibanaDirector `${kibanaDirectory}/src/dev/jest/setup/react_testing_library.js`, ], testEnvironment: 'jest-environment-jsdom-thirteen', - testMatch: ['**/*.test.{js,ts,tsx}'], + testMatch: ['**/*.test.{js,mjs,ts,tsx}'], testRunner: 'jest-circus/runner', transform: { '^.+\\.(js|tsx?)$': `${kibanaDirectory}/src/dev/jest/babel_transform.js`, diff --git a/x-pack/plugins/apm/jest.config.js b/x-pack/plugins/apm/jest.config.js index 43bdeb583c819e..2f9d8a37376d96 100644 --- a/x-pack/plugins/apm/jest.config.js +++ b/x-pack/plugins/apm/jest.config.js @@ -29,10 +29,10 @@ module.exports = { roots: [`${rootDir}/common`, `${rootDir}/public`, `${rootDir}/server`], collectCoverage: true, collectCoverageFrom: [ - '**/*.{js,jsx,ts,tsx}', + '**/*.{js,mjs,jsx,ts,tsx}', '!**/{__test__,__snapshots__,__examples__,integration_tests,tests}/**', - '!**/*.stories.{js,ts,tsx}', - '!**/*.test.{js,ts,tsx}', + '!**/*.stories.{js,mjs,ts,tsx}', + '!**/*.test.{js,mjs,ts,tsx}', '!**/dev_docs/**', '!**/e2e/**', '!**/scripts/**', diff --git a/x-pack/test_utils/jest/config.integration.js b/x-pack/test_utils/jest/config.integration.js index 033c948c3c0343..03917d34ab09ca 100644 --- a/x-pack/test_utils/jest/config.integration.js +++ b/x-pack/test_utils/jest/config.integration.js @@ -10,9 +10,9 @@ import config from './config'; export default { ...config, testMatch: [ - `**/${RESERVED_DIR_JEST_INTEGRATION_TESTS}/**/*.test.{js,ts,tsx}`, + `**/${RESERVED_DIR_JEST_INTEGRATION_TESTS}/**/*.test.{js,mjs,ts,tsx}`, // Tests within `__jest__` directories should be treated as regular unit tests. - `!**/__jest__/${RESERVED_DIR_JEST_INTEGRATION_TESTS}/**/*.test.{js,ts,tsx}`, + `!**/__jest__/${RESERVED_DIR_JEST_INTEGRATION_TESTS}/**/*.test.{js,mjs,ts,tsx}`, ], testPathIgnorePatterns: config.testPathIgnorePatterns.filter( (pattern) => !pattern.includes(RESERVED_DIR_JEST_INTEGRATION_TESTS) diff --git a/x-pack/test_utils/jest/config.js b/x-pack/test_utils/jest/config.js index adee510ef28467..7bb073023b7f8b 100644 --- a/x-pack/test_utils/jest/config.js +++ b/x-pack/test_utils/jest/config.js @@ -29,10 +29,10 @@ export default { ], coverageDirectory: '/../target/kibana-coverage/jest', coverageReporters: ['html'], - moduleFileExtensions: ['js', 'json', 'ts', 'tsx', 'node'], + moduleFileExtensions: ['js', 'mjs', 'json', 'ts', 'tsx', 'node'], modulePathIgnorePatterns: ['__fixtures__/', 'target/'], testEnvironment: 'jest-environment-jsdom-thirteen', - testMatch: ['**/*.test.{js,ts,tsx}'], + testMatch: ['**/*.test.{js,mjs,ts,tsx}'], testPathIgnorePatterns: [ '/packages/kbn-ui-framework/(dist|doc_site|generator-kui)/', '/packages/kbn-pm/dist/', From 93ef5c0c418374fdd145a3ed321fa6700a8132e3 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Tue, 30 Jun 2020 07:30:31 -0700 Subject: [PATCH 10/13] [Usage Collection] Report nodes feature usage (#70108) * Adds nodes feature usage stats merged into cluster_stats.nodes when usage collection is local --- .../__tests__/get_local_stats.js | 65 +++++++++++++-- .../telemetry_collection/get_local_stats.ts | 14 +++- .../get_nodes_usage.test.ts | 80 ++++++++++++++++++ .../telemetry_collection/get_nodes_usage.ts | 81 +++++++++++++++++++ .../apis/telemetry/telemetry_local.js | 1 + .../get_stats_with_xpack.test.ts.snap | 44 +++++++++- .../get_stats_with_xpack.test.ts | 25 ++++++ 7 files changed, 299 insertions(+), 11 deletions(-) create mode 100644 src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts create mode 100644 src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts diff --git a/src/plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js b/src/plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js index 29076537e9ae88..e78b92498e6e78 100644 --- a/src/plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js +++ b/src/plugins/telemetry/server/telemetry_collection/__tests__/get_local_stats.js @@ -19,11 +19,12 @@ import expect from '@kbn/expect'; import sinon from 'sinon'; +import { merge, omit } from 'lodash'; +import { TIMEOUT } from '../constants'; import { mockGetClusterInfo } from './get_cluster_info'; import { mockGetClusterStats } from './get_cluster_stats'; -import { omit } from 'lodash'; import { getLocalStats, handleLocalStats } from '../get_local_stats'; const mockUsageCollection = (kibanaUsage = {}) => ({ @@ -51,10 +52,26 @@ const getMockServer = (getCluster = sinon.stub()) => ({ elasticsearch: { getCluster }, }, }); +function mockGetNodesUsage(callCluster, nodesUsage, req) { + callCluster + .withArgs( + req, + { + method: 'GET', + path: '/_nodes/usage', + query: { + timeout: TIMEOUT, + }, + }, + 'transport.request' + ) + .returns(nodesUsage); +} -function mockGetLocalStats(callCluster, clusterInfo, clusterStats, req) { +function mockGetLocalStats(callCluster, clusterInfo, clusterStats, nodesUsage, req) { mockGetClusterInfo(callCluster, clusterInfo, req); mockGetClusterStats(callCluster, clusterStats, req); + mockGetNodesUsage(callCluster, nodesUsage, req); } describe('get_local_stats', () => { @@ -68,6 +85,28 @@ describe('get_local_stats', () => { number: version, }, }; + const nodesUsage = [ + { + node_id: 'some_node_id', + timestamp: 1588617023177, + since: 1588616945163, + rest_actions: { + nodes_usage_action: 1, + create_index_action: 1, + document_get_action: 1, + search_action: 19, + nodes_info_action: 36, + }, + aggregations: { + terms: { + bytes: 2, + }, + scripted_metric: { + other: 7, + }, + }, + }, + ]; const clusterStats = { _nodes: { failed: 123 }, cluster_name: 'real-cool', @@ -75,6 +114,7 @@ describe('get_local_stats', () => { nodes: { yup: 'abc' }, random: 123, }; + const kibana = { kibana: { great: 'googlymoogly', @@ -97,12 +137,16 @@ describe('get_local_stats', () => { snow: { chances: 0 }, }; + const clusterStatsWithNodesUsage = { + ...clusterStats, + nodes: merge(clusterStats.nodes, { usage: nodesUsage }), + }; const combinedStatsResult = { collection: 'local', cluster_uuid: clusterUuid, cluster_name: clusterName, version, - cluster_stats: omit(clusterStats, '_nodes', 'cluster_name'), + cluster_stats: omit(clusterStatsWithNodesUsage, '_nodes', 'cluster_name'), stack_stats: { kibana: { great: 'googlymoogly', @@ -135,7 +179,7 @@ describe('get_local_stats', () => { describe('handleLocalStats', () => { it('returns expected object without xpack and kibana data', () => { - const result = handleLocalStats(clusterInfo, clusterStats, void 0, context); + const result = handleLocalStats(clusterInfo, clusterStatsWithNodesUsage, void 0, context); expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid); expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name); expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats); @@ -146,7 +190,7 @@ describe('get_local_stats', () => { }); it('returns expected object with xpack', () => { - const result = handleLocalStats(clusterInfo, clusterStats, void 0, context); + const result = handleLocalStats(clusterInfo, clusterStatsWithNodesUsage, void 0, context); const { stack_stats: stack, ...cluster } = result; expect(cluster.collection).to.be(combinedStatsResult.collection); expect(cluster.cluster_uuid).to.be(combinedStatsResult.cluster_uuid); @@ -167,7 +211,8 @@ describe('get_local_stats', () => { mockGetLocalStats( callClusterUsageFailed, Promise.resolve(clusterInfo), - Promise.resolve(clusterStats) + Promise.resolve(clusterStats), + Promise.resolve(nodesUsage) ); const result = await getLocalStats([], { server: getMockServer(), @@ -177,6 +222,7 @@ describe('get_local_stats', () => { expect(result.cluster_uuid).to.eql(combinedStatsResult.cluster_uuid); expect(result.cluster_name).to.eql(combinedStatsResult.cluster_name); expect(result.cluster_stats).to.eql(combinedStatsResult.cluster_stats); + expect(result.cluster_stats.nodes).to.eql(combinedStatsResult.cluster_stats.nodes); expect(result.version).to.be('2.3.4'); expect(result.collection).to.be('local'); @@ -188,7 +234,12 @@ describe('get_local_stats', () => { it('returns expected object with xpack and kibana data', async () => { const callCluster = sinon.stub(); const usageCollection = mockUsageCollection(kibana); - mockGetLocalStats(callCluster, Promise.resolve(clusterInfo), Promise.resolve(clusterStats)); + mockGetLocalStats( + callCluster, + Promise.resolve(clusterInfo), + Promise.resolve(clusterStats), + Promise.resolve(nodesUsage) + ); const result = await getLocalStats([], { server: getMockServer(callCluster), diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts index b77d01c5b431fd..b42edde2f55ca2 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.ts @@ -24,6 +24,7 @@ import { import { getClusterInfo, ESClusterInfo } from './get_cluster_info'; import { getClusterStats } from './get_cluster_stats'; import { getKibana, handleKibanaStats, KibanaUsageStats } from './get_kibana'; +import { getNodesUsage } from './get_nodes_usage'; /** * Handle the separate local calls by combining them into a single object response that looks like the @@ -67,12 +68,21 @@ export const getLocalStats: StatsGetter<{}, TelemetryLocalStats> = async ( return await Promise.all( clustersDetails.map(async (clustersDetail) => { - const [clusterInfo, clusterStats, kibana] = await Promise.all([ + const [clusterInfo, clusterStats, nodesUsage, kibana] = await Promise.all([ getClusterInfo(callCluster), // cluster info getClusterStats(callCluster), // cluster stats (not to be confused with cluster _state_) + getNodesUsage(callCluster), // nodes_usage info getKibana(usageCollection, callCluster), ]); - return handleLocalStats(clusterInfo, clusterStats, kibana, context); + return handleLocalStats( + clusterInfo, + { + ...clusterStats, + nodes: { ...clusterStats.nodes, usage: nodesUsage }, + }, + kibana, + context + ); }) ); }; diff --git a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts new file mode 100644 index 00000000000000..4e4b0e11b79794 --- /dev/null +++ b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getNodesUsage } from './get_nodes_usage'; +import { TIMEOUT } from './constants'; + +const mockedNodesFetchResponse = { + cluster_name: 'test cluster', + nodes: { + some_node_id: { + timestamp: 1588617023177, + since: 1588616945163, + rest_actions: { + nodes_usage_action: 1, + create_index_action: 1, + document_get_action: 1, + search_action: 19, + nodes_info_action: 36, + }, + aggregations: { + terms: { + bytes: 2, + }, + scripted_metric: { + other: 7, + }, + }, + }, + }, +}; +describe('get_nodes_usage', () => { + it('calls fetchNodesUsage', async () => { + const callCluster = jest.fn(); + callCluster.mockResolvedValueOnce(mockedNodesFetchResponse); + await getNodesUsage(callCluster); + expect(callCluster).toHaveBeenCalledWith('transport.request', { + path: '/_nodes/usage', + method: 'GET', + query: { + timeout: TIMEOUT, + }, + }); + }); + it('returns a modified array of node usage data', async () => { + const callCluster = jest.fn(); + callCluster.mockResolvedValueOnce(mockedNodesFetchResponse); + const result = await getNodesUsage(callCluster); + expect(result.nodes).toEqual([ + { + aggregations: { scripted_metric: { other: 7 }, terms: { bytes: 2 } }, + node_id: 'some_node_id', + rest_actions: { + create_index_action: 1, + document_get_action: 1, + nodes_info_action: 36, + nodes_usage_action: 1, + search_action: 19, + }, + since: 1588616945163, + timestamp: 1588617023177, + }, + ]); + }); +}); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts new file mode 100644 index 00000000000000..c5c110fbb4149b --- /dev/null +++ b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.ts @@ -0,0 +1,81 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { LegacyAPICaller } from 'kibana/server'; +import { TIMEOUT } from './constants'; + +export interface NodeAggregation { + [key: string]: number; +} + +// we set aggregations as an optional type because it was only added in v7.8.0 +export interface NodeObj { + node_id?: string; + timestamp: number; + since: number; + rest_actions: { + [key: string]: number; + }; + aggregations?: { + [key: string]: NodeAggregation; + }; +} + +export interface NodesFeatureUsageResponse { + cluster_name: string; + nodes: { + [key: string]: NodeObj; + }; +} + +export type NodesUsageGetter = ( + callCluster: LegacyAPICaller +) => Promise<{ nodes: NodeObj[] | Array<{}> }>; +/** + * Get the nodes usage data from the connected cluster. + * + * This is the equivalent to GET /_nodes/usage?timeout=30s. + * + * The Nodes usage API was introduced in v6.0.0 + */ +export async function fetchNodesUsage( + callCluster: LegacyAPICaller +): Promise { + const response = await callCluster('transport.request', { + method: 'GET', + path: '/_nodes/usage', + query: { + timeout: TIMEOUT, + }, + }); + return response; +} + +/** + * Get the nodes usage from the connected cluster + * @param callCluster APICaller + * @returns Object containing array of modified usage information with the node_id nested within the data for that node. + */ +export const getNodesUsage: NodesUsageGetter = async (callCluster) => { + const result = await fetchNodesUsage(callCluster); + const transformedNodes = Object.entries(result?.nodes || {}).map(([key, value]) => ({ + ...(value as NodeObj), + node_id: key, + })); + return { nodes: transformedNodes }; +}; diff --git a/test/api_integration/apis/telemetry/telemetry_local.js b/test/api_integration/apis/telemetry/telemetry_local.js index 2875ff09a9a8d0..e74cd180185ab3 100644 --- a/test/api_integration/apis/telemetry/telemetry_local.js +++ b/test/api_integration/apis/telemetry/telemetry_local.js @@ -113,6 +113,7 @@ export default function ({ getService }) { 'cluster_stats.nodes.plugins', 'cluster_stats.nodes.process', 'cluster_stats.nodes.versions', + 'cluster_stats.nodes.usage', 'cluster_stats.status', 'cluster_stats.timestamp', 'cluster_uuid', diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap index 1a70504dc93918..ed82dc65eb4108 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/__snapshots__/get_stats_with_xpack.test.ts.snap @@ -4,7 +4,27 @@ exports[`Telemetry Collection: Get Aggregated Stats OSS-like telemetry (no licen Array [ Object { "cluster_name": "test", - "cluster_stats": Object {}, + "cluster_stats": Object { + "nodes": Object { + "usage": Object { + "nodes": Array [ + Object { + "aggregations": Object { + "terms": Object { + "bytes": 2, + }, + }, + "node_id": "some_node_id", + "rest_actions": Object { + "nodes_usage_action": 1, + }, + "since": 1588616945163, + "timestamp": 1588617023177, + }, + ], + }, + }, + }, "cluster_uuid": "test", "collection": "local", "stack_stats": Object { @@ -62,7 +82,27 @@ exports[`Telemetry Collection: Get Aggregated Stats X-Pack telemetry (license + Array [ Object { "cluster_name": "test", - "cluster_stats": Object {}, + "cluster_stats": Object { + "nodes": Object { + "usage": Object { + "nodes": Array [ + Object { + "aggregations": Object { + "terms": Object { + "bytes": 2, + }, + }, + "node_id": "some_node_id", + "rest_actions": Object { + "nodes_usage_action": 1, + }, + "since": 1588616945163, + "timestamp": 1588617023177, + }, + ], + }, + }, + }, "cluster_uuid": "test", "collection": "local", "stack_stats": Object { diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts index 5dfe3d3e99a7f3..a8311933f05317 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts @@ -28,6 +28,20 @@ const kibana = { rain: { chances: 2 }, snow: { chances: 0 }, }; +const nodesUsage = { + some_node_id: { + timestamp: 1588617023177, + since: 1588616945163, + rest_actions: { + nodes_usage_action: 1, + }, + aggregations: { + terms: { + bytes: 2, + }, + }, + }, +}; const getContext = () => ({ version: '8675309-snapshot', @@ -47,6 +61,11 @@ describe('Telemetry Collection: Get Aggregated Stats', () => { if (options.path === '/_license' || options.path === '/_xpack/usage') { // eslint-disable-next-line no-throw-literal throw { statusCode: 404 }; + } else if (options.path === '/_nodes/usage') { + return { + cluster_name: 'test cluster', + nodes: nodesUsage, + }; } return {}; case 'info': @@ -81,6 +100,12 @@ describe('Telemetry Collection: Get Aggregated Stats', () => { if (options.path === '/_xpack/usage') { return {}; } + if (options.path === '/_nodes/usage') { + return { + cluster_name: 'test cluster', + nodes: nodesUsage, + }; + } case 'info': return { cluster_uuid: 'test', cluster_name: 'test', version: { number: '8.0.0' } }; default: From 8978ec8945df57b5df76a3b404b1bf35e0762c91 Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Tue, 30 Jun 2020 07:31:47 -0700 Subject: [PATCH 11/13] [DOCS] Adds glossary to documentation (#69721) * [DOCS] Adds glossary to documentation * [DOCS] Fixes build errors * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * [DOCS] Adds more terms to glossary * [DOCS] Adds more terms to glossary * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * Update docs/glossary.asciidoc Co-authored-by: debadair * [DOCS] Incorporates review comments * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * Update docs/glossary.asciidoc Co-authored-by: Lisa Cawley * [DOCS] Incorporates review comments * [DOCS] Incorporates review comments Co-authored-by: Lisa Cawley Co-authored-by: debadair --- docs/glossary.asciidoc | 413 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 docs/glossary.asciidoc diff --git a/docs/glossary.asciidoc b/docs/glossary.asciidoc new file mode 100644 index 00000000000000..d7a82068abbcb7 --- /dev/null +++ b/docs/glossary.asciidoc @@ -0,0 +1,413 @@ +[glossary] +[[glossary]] += Glossary + +<> | <> | <> | <> | <> | <> | <> | H | I | J | <> | <> | <> | N | O | <> | <> | R | <> | <> | <> | V | <> | X | Y | Z + +[float] +[[a_glos]] +== A + +[glossary] +[[glossary-action]] action :: ++ +-- +// tag::action-def[] +The alert-specific response that occurs when an alert fires. +An alert can have multiple actions. +See +{kibana-ref}/action-types.html[Action and connector types]. +// end::action-def[] +-- + +[[glossary-advanced-settings]] Advanced Settings :: +// tag::advanced-settings-def[] +Enables you to control the appearance and behavior of {kib} +by setting the date format, default index, and other attributes. +Part of {kib} Stack Management. +See {kibana-ref}/advanced-options.html[Advanced Settings]. +// end::advanced-settings-def[] + +[[glossary-alert]] alert :: +// tag::alert-def[] +A set of <>, schedules, and <> +that enable notifications. +See <>. +// end::alert-def[] + +[[glossary-alerts-and-actions]] Alerts and Actions :: +// tag::alerts-and-actions-def[] +A comprehensive view of all your alerts. Enables you to access and +manage alerts for all {kib} apps from one place. +See {kibana-ref}/alerting-getting-started.html[Alerts and Actions]. +// end::alerts-and-actions-def[] + +[[glossary-annotation]] annotation :: +// tag::annotation-def[] +A way to augment a data display with descriptive domain knowledge. +// end::alerts-annotation-def[] + + +[[glossary-app]] app :: +// tag::app-def[] +A top-level {kib} component that is accessed through the side navigation. +Apps include core {kib} components such as Discover and Dashboard, +solutions like Observability and Security, and special-purpose tools +like Maps and Stack Management. +// end::app-def[] + + +[float] +[[b_glos]] +== B + +[[glossary-basemap]] basemap :: +// tag::basemap-def[] +The background detail necessary to orient the location of a map. +// end::basemap-def[] + +[[glossary-bucket]] bucket :: +// tag::bucket-def[] +A set of documents in {kib} that have certain characteristics in common. +For example, matching documents might be bucketed by color, distance, or date range. +// end::bucket-def[] + +[[glossary-bucket-aggregation]] bucket aggregation:: +// tag::bucket-aggregation-def[] +An aggregation that creates buckets of documents. Each bucket is associated with a +criterion (depending on the aggregation type), which determines whether or not a document +in the current context falls into the bucket. +// end::bucket-aggregation-def[] + +[float] +[[c_glos]] +== C + +[[glossary-canvas]] Canvas :: +// tag::canvas-def[] +Enables you to create presentations and infographics that pull live data directly from {es}. +See {kibana-ref}/canvas.html[Canvas]. +// end::canvas-def[] + +[[glossary-canvas-language]] Canvas expression language:: +// tag::ccanvas-language-def[] +A pipeline-based expression language for manipulating and visualizing data. +Includes dozens of functions and other capabilities, such as table transforms, +type casting, and sub-expressions. Supports TinyMath functions for complex math calculations. +See {kibana-ref}/canvas-function-reference.html[Canvas function reference]. +// end::canvas-language-def[] + + +[[glossary-certainty]] certainty :: +// tag::certainty-def[] +Specifies how many documents must contain a pair of terms before it is considered +a useful connection in a graph. +// end::certainty-def[] + +[[glossary-condition]] condition :: +// tag::condition-def[] +Specifies the circumstances that must be met to trigger an alert. +// end::condition-def[] + +[[glossary-connector]] connector :: +// tag::connector-def[] +A configuration that enables integration with an external system (the destination for an action). +See {kibana-ref}/action-types.html[Action and connector types]. +// end::connector-def[] + +[[glossary-console]] Console :: +// tag::console-def[] +A tool for interacting with the {es} REST API. +You can send requests to {es}, view responses, +view API documentation, and get your request history. +See {kibana-ref}/console-kibana.html[Console]. +// end::console-def[] + +[float] +[[d_glos]] +== D + +[[glossary-dashboard]] dashboard :: +// tag::dashboard-def[] +A collection of +<>, <>, and +<> that +provide insights into your data from multiple perspectives. +// end::dashboard-def[] + +[[glossary-data-source]] data source :: +// tag::data-source-def[] +A file, database, or service that provides the underlying data for a map, Canvas element, or visualization. +// end::data-source-def[] + +[[glossary-discover]] Discover :: +// tag::discover-def[] +Enables you to search and filter your data to zoom in on the information +that you are interested in. +// end::discover-def[] + +[[glossary-drilldown]] drilldown :: +// tag::drilldown-def[] +A navigation path that retains context (time range and filters) +from the source to the destination, so you can view the data from a new perspective. +A dashboard that shows the overall status of multiple data centers +might have a drilldown to a dashboard for a single data center. See {kibana-ref}/drilldowns.html[Drilldowns]. +// end::drilldown-def[] + + + +[float] +[[e_glos]] +== E + +[[glossary-edge]] edge :: +// tag::edge-def[] +A connection between nodes in a graph that shows that they are related. +The line weight indicates the strength of the relationship. See +{kibana-ref}/xpack-graph.html[Graph]. +// end::edge-def[] + + +[[glossary-ems]] Elastic Maps Service (EMS) :: +// tag::ems-def[] +A service that provides basemap tiles, shape files, and other key features +that are essential for visualizing geospatial data. +// end::ems-def[] + +[[glossary-element]] element :: +// tag::element-def[] +A <> workpad object that displays an image, text, or visualization. +// end::element-def[] + + +[float] +[[f_glos]] +== F + +[[glossary-feature-controls]] Feature Controls :: +// tag::feature-controls-def[] +Enables administrators to customize which features are +available in each <>. See +{kibana-ref}//xpack-spaces.html#spaces-control-feature-visibility[Feature Controls]. +// end::feature-controls-def[] + +[float] +[[g_glos]] +== G + +[[glossary-graph]] graph :: +// tag::graph-def[] +A data structure and visualization that shows interconnections between +a set of entities. Each entity is represented by a node. Connections between +nodes are represented by <>. See {kibana-ref}/xpack-graph.html[Graph]. +// end::graph-def[] + +[[glossary-grok-debugger]] Grok Debugger :: +// tag::grok-debugger-def[] +A tool for building and debugging grok patterns. Grok is good for parsing +syslog, Apache, and other webserver logs. See +{kibana-ref}/xpack-grokdebugger.html[Debugging grok expressions]. +// end::grok-debugger-def[] + + +[float] +[[k_glos]] +== K + +[[glossary-kql]] {kib} Query Language (KQL) :: +// tag::kql-def[] +The default language for querying in {kib}. KQL provides +support for scripted fields. See +{kibana-ref}/kuery-query.html[Kibana Query Language]. +// end::kql-def[] + + +[float] +[[l_glos]] +== L + +[[glossary-lens]] Lens :: +// tag::lens-def[] +Enables you to build visualizations by dragging and dropping data fields. +Lens makes makes smart visualization suggestions for your data, +allowing you to switch between visualization types. +See {kibana-ref}/lens.html[Lens]. +// end::lens-def[] + + +[[glossary-lucene]] Lucene query syntax :: +// tag::lucene-def[] +The query syntax for {kib}’s legacy query language. The Lucene query +syntax is available under the options menu in the query bar and from +<>. +// end::lucene-def[] + +[float] +[[m_glos]] +== M + +[[glossary-map]] map :: +// tag::map-def[] +A representation of geographic data using symbols and labels. +See {kibana-ref}/maps.html[Maps]. +// end::map-def[] + +[[glossary-metric-aggregation]] metric aggregation :: +// tag::metric-aggregation-def[] +An aggregation that calculates and tracks metrics for a set of documents. +// end::metric-aggregation-def[] + + +[float] +[[p_glos]] +== P + +[[glossary-painless-lab]] Painless Lab :: +// tag::painless-lab-def[] +An interactive code editor that lets you test and debug Painless scripts in real-time. +See {kibana-ref}/painlesslab.html[Painless Lab]. +// end::painless-lab-def[] + + +[[glossary-panel]] panel :: +// tag::panel-def[] +A <> component that contains a +query element or visualization, such as a chart, table, or list. +// end::panel-def[] + + +[float] +[[q_glos]] +== Q + +[[glossary-query-profiler]] Query Profiler :: +// tag::query-profiler-def[] +A tool that enables you to inspect and analyze search queries to diagnose and debug poorly performing queries. +See {kibana-ref}/xpack-profiler.html[Query Profiler]. +// end::query-profiler-def[] + +[float] +[[s_glos]] +== S + +[[glossary-saved-object]] saved object :: +// tag::saved-object-def[] +A representation of a dashboard, visualization, map, index pattern, or Canvas workpad +that can be stored and reloaded. +// end::saved-object-def[] + +[[glossary-saved-search]] saved search :: +// tag::saved-search-def[] +The query text, filters, and time filter that make up a search, +saved for later retrieval and reuse. +// end::saved-search-def[] + +[[glossary-scripted-field]] scripted field :: +// tag::scripted-field-def[] +A field that computes data on the fly from the data in {es} indices. +Scripted field data is shown in Discover and used in visualizations. +// end::scripted-field-def[] + +[[glossary-shareable]] shareable :: +// tag::shareable-def[] +A Canvas workpad that can be embedded on any webpage. +Shareables enable you to display Canvas visualizations on internal wiki pages or public websites. +// end::shareable-def[] + +[[glossary-space]] space :: +// tag::space-def[] +A place for organizing <>, +<>, and other <> by category. +For example, you might have different spaces for each team, use case, or individual. +See +{kibana-ref}/xpack-spaces.html[Spaces]. +// end::space-def[] + + +[float] +[[t_glos]] +== T + +[[glossary-term-join]] term join :: +// tag::term-join-def[] +A shared key that combines vector features with the results of an +{es} terms aggregation. Term joins augment vector features with +properties for data-driven styling and rich tooltip content in maps. +// end::term-join-def[] + +[[glossary-time-filter]] time filter :: +// tag::time-filter-def[] +A {kib} control that constrains the search results to a particular time period. +// end::time-filter-def[] + +[[glossary-timelion]] Timelion :: +// tag::timelion-def[] +A tool for building a time series visualization that analyzes data in time order. +See {kibana-ref}/timelion.html[Timelion]. +// end::timelion-def[] + + +[[glossary-time-series-data]] time series data :: +// tag::time-series-data-def[] +Timestamped data such as logs, metrics, and events that is indexed on an ongoing basis. +// end::time-series-data-def[] + + +[[glossary-TSVB-data]] TSVB :: +// tag::TSVB-def[] +A time series data visualizer that allows you to combine an +infinite number of aggregations to display complex data. +See {kibana-ref}/TSVB.html[TSVB]. +// end::TSVB-def[] + + +[float] +[[u_glos]] +== U + +[[glossary-upgrade-assistant]] Upgrade Assistant :: +// tag::upgrade-assistant-def[] +A tool that helps you prepare for an upgrade to the next major version of +{es}. The assistant identifies the deprecated settings in your cluster and +indices and guides you through resolving issues, including reindexing. See +{kibana-ref}/upgrade-assistant.html[Upgrade Assistant]. +// end::upgrade-assistant-def[] + + +[float] +[[v_glos]] +== V + +[[glossary-vega]] Vega :: +// tag::vega-def[] +A declarative language used to create interactive visualizations. +See {kibana-ref}/vega-graph.html[Vega]. +// end::vega-def[] + +[[glossary-vector]] vector data:: +// tag::vector-def[] +Points, lines, and polygons used to represent a map. +// end::vector-def[] + +[[glossary-visualization]] visualization :: +// tag::visualization-def[] +A graphical representation of query results in {kib} (e.g., a histogram, line graph, pie chart, or heat map). +// end::visualization-def[] + +[float] +[[w_glos]] +== W + +[[glossary-watcher]] Watcher :: +// tag::watcher-def[] +The original suite of alerting features. +See +{kibana-ref}/watcher-ui.html[Watcher]. +// end::watcher-def[] + +[[glossary-workpad]] workpad :: +// tag::workpad-def[] +A workspace where you build presentations of your live data in <>. +See +{kibana-ref}/create-canvas-workpad.html[Create a workpad]. +// end::workpad-def[] From 606eb6b3d864dda97edae08d932252b6e9b198db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 30 Jun 2020 16:35:52 +0200 Subject: [PATCH 12/13] [APM] Add API test for service maps (#70185) * [APM] Add API test for service maps * Re-add custom links test * Improved test names * Disable eslint rule * Undo readme changes * Fix ts errors --- .eslintrc.js | 1 + .../test/apm_api_integration/basic/config.ts | 1 - .../basic/tests/agent_configuration.ts | 1 - .../basic/tests/annotations.ts | 1 - .../basic/tests/custom_link.ts | 1 - .../basic/tests/feature_controls.ts | 1 - .../apm_api_integration/basic/tests/index.ts | 2 +- .../basic/tests/service_maps.ts | 25 + .../test/apm_api_integration/trial/config.ts | 1 - .../fixtures/es_archiver/8.0.0/data.json.gz | Bin 0 -> 193103 bytes .../fixtures/es_archiver/8.0.0/mappings.json | 25698 ++++++++++++++++ .../trial/tests/annotations.ts | 1 - .../apm_api_integration/trial/tests/index.ts | 2 +- .../trial/tests/service_maps.ts | 261 + 14 files changed, 25987 insertions(+), 9 deletions(-) create mode 100644 x-pack/test/apm_api_integration/basic/tests/service_maps.ts create mode 100644 x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz create mode 100644 x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/mappings.json create mode 100644 x-pack/test/apm_api_integration/trial/tests/service_maps.ts diff --git a/.eslintrc.js b/.eslintrc.js index 2c49bf78c67b16..8d979dc0f8645e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -334,6 +334,7 @@ module.exports = { */ { files: [ + 'x-pack/test/apm_api_integration/**/*.ts', 'x-pack/test/functional/apps/**/*.js', 'x-pack/plugins/apm/**/*.js', 'test/*/config.ts', diff --git a/x-pack/test/apm_api_integration/basic/config.ts b/x-pack/test/apm_api_integration/basic/config.ts index 541fe9ec023bcf..03b8b21bf3232e 100644 --- a/x-pack/test/apm_api_integration/basic/config.ts +++ b/x-pack/test/apm_api_integration/basic/config.ts @@ -6,7 +6,6 @@ import { createTestConfig } from '../common/config'; -// eslint-disable-next-line import/no-default-export export default createTestConfig({ license: 'basic', name: 'X-Pack APM API integration tests (basic)', diff --git a/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts b/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts index 9f39da2037f8ea..7b99622cc46579 100644 --- a/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts +++ b/x-pack/test/apm_api_integration/basic/tests/agent_configuration.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import { AgentConfigurationIntake } from '../../../../plugins/apm/common/agent_configuration/configuration_types'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default function agentConfigurationTests({ getService }: FtrProviderContext) { const supertestRead = getService('supertestAsApmReadUser'); const supertestWrite = getService('supertestAsApmWriteUser'); diff --git a/x-pack/test/apm_api_integration/basic/tests/annotations.ts b/x-pack/test/apm_api_integration/basic/tests/annotations.ts index c522ebcfb5c65e..e0659fe195f931 100644 --- a/x-pack/test/apm_api_integration/basic/tests/annotations.ts +++ b/x-pack/test/apm_api_integration/basic/tests/annotations.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import { JsonObject } from 'src/plugins/kibana_utils/common'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default function annotationApiTests({ getService }: FtrProviderContext) { const supertestWrite = getService('supertestAsApmAnnotationsWriteUser'); diff --git a/x-pack/test/apm_api_integration/basic/tests/custom_link.ts b/x-pack/test/apm_api_integration/basic/tests/custom_link.ts index 77fdc83523ca64..ec93d2b3a3b411 100644 --- a/x-pack/test/apm_api_integration/basic/tests/custom_link.ts +++ b/x-pack/test/apm_api_integration/basic/tests/custom_link.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import { CustomLink } from '../../../../plugins/apm/common/custom_link/custom_link_types'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default function customLinksTests({ getService }: FtrProviderContext) { const supertestRead = getService('supertestAsApmReadUser'); const supertestWrite = getService('supertestAsApmWriteUser'); diff --git a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts index 42cbef69abbec9..400d0d294bf02e 100644 --- a/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts +++ b/x-pack/test/apm_api_integration/basic/tests/feature_controls.ts @@ -7,7 +7,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default function featureControlsTests({ getService }: FtrProviderContext) { const supertest = getService('supertestAsApmWriteUser'); const supertestWithoutAuth = getService('supertestWithoutAuth'); diff --git a/x-pack/test/apm_api_integration/basic/tests/index.ts b/x-pack/test/apm_api_integration/basic/tests/index.ts index 7c7e5a8dd93cc6..02185b0761c5b6 100644 --- a/x-pack/test/apm_api_integration/basic/tests/index.ts +++ b/x-pack/test/apm_api_integration/basic/tests/index.ts @@ -5,7 +5,6 @@ */ import { FtrProviderContext } from '../../common/ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderContext) { describe('APM specs (basic)', function () { this.tags('ciGroup1'); @@ -14,5 +13,6 @@ export default function apmApiIntegrationTests({ loadTestFile }: FtrProviderCont loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./agent_configuration')); loadTestFile(require.resolve('./custom_link')); + loadTestFile(require.resolve('./service_maps')); }); } diff --git a/x-pack/test/apm_api_integration/basic/tests/service_maps.ts b/x-pack/test/apm_api_integration/basic/tests/service_maps.ts new file mode 100644 index 00000000000000..64910d2b45632a --- /dev/null +++ b/x-pack/test/apm_api_integration/basic/tests/service_maps.ts @@ -0,0 +1,25 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +export default function serviceMapsApiTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('Service Maps', () => { + it('should only be available to users with Platinum license (or higher)', async () => { + const response = await supertest.get( + '/api/apm/service-map?start=2020-06-28T10%3A24%3A46.055Z&end=2020-06-29T10%3A24%3A46.055Z' + ); + + expect(response.status).to.be(403); + expect(response.body.message).to.be( + "In order to access Service Maps, you must be subscribed to an Elastic Platinum license. With it, you'll have the ability to visualize your entire application stack along with your APM data." + ); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/trial/config.ts b/x-pack/test/apm_api_integration/trial/config.ts index ca5b11d469c470..94a6f808603c11 100644 --- a/x-pack/test/apm_api_integration/trial/config.ts +++ b/x-pack/test/apm_api_integration/trial/config.ts @@ -6,7 +6,6 @@ import { createTestConfig } from '../common/config'; -// eslint-disable-next-line import/no-default-export export default createTestConfig({ license: 'trial', name: 'X-Pack APM API integration tests (trial)', diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz b/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..e9360878b7bb724924c89bbaea7b243a555f13d3 GIT binary patch literal 193103 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
#xkG+Z- z8}lrfFkXDbJx%pQDY2o?{cx#UwSCiOuD)Y)6U#f?7c5-g!g0Z9W3eOEQ;0sH0Sye{ zllwi5@lYjhTFN7``&+Ii@2LaXE60f7D8DRKA+CI`bkzG^GJ`n0sne`ue1CzvcYN+>R&G zy6Bug?o#zs)vivp&u#rg137+1_miggnz|v#QQLX=6vJ1VkEY~!@f$sG;fKbTOOz^H z1+iGUXy zV&ul7A4I5+!&{DapS)Cx#m&>yF>;a2F_y-`X;{Yyt`8%0i*XuHV3YTN_u0p~$}#=f zgY}}7B)GEq37x=U$ndE!L%>Cs*!G-T&rp%+S?H+Ja>H}Qrekf22)D@!{@&LSt@YB=CYR^#Ycd>@*xyc+f zXZSOZDnp&)eu`V-oGNS=JcA2Xz%|$Lb(Iy@yNekB1*pVnIc1Y&!wKoJ=0}9wIeeLO z&8+5o+t&E|d-}VdY|e3>VYAhVj$i(dtgGsfZF^tMd{mzD>6Mk1Lt)h8FJAV*;O<%` z>y0d`{0u%AzS60;mN8K7cFp9|vCpPDN0*S~54BQQHKdWeKX#YMqjm@YKwxojLDNnD zJDW$(odK(Z;eI8L5A}^3>I~>w#Pa7L$ID+|pT1x94MUd&7HJbehM(Ll?j!l*5)CGD<2wn}G5-}5bWg`?ug!DXJ zh|QCXQxP6SP#<0jVyQQU zmEl$PvO$w(W8a5SS3y0=0$`rywGY(%5S%s#^XQwY&x*_P zys{|rZ*Sczg?cPmWT$Fo(tHvooU)M3%}#b*rTk_(-JACBPSvp_gz6S<3mUI=wBBVQ zav{_I7AgffZ(T23%*3_Pkh$- zKB!#^3zq5CU-_vYIta-M`LrjsX+T9z2BFUzOfO{3@sA6 zu~|QQVm%Bvc&=bmwd~KEH9@w5cv(6iYPU5*Jd+ws1TQaUcr$j7npH0?x$lq~vjwOw zp-PP|ydLv$k0qY!Xx%@rg>s2L2mDHMdF8nepRD?*jLDlbjl9`X^0)#g`(Ax(yQch$ zEN_c^A)O}Zn*f{Bnzv-<-3ZrxS49(cKqqQF!q=lB!^Fu95>FGEV^fIMg&1(^x@ghupkQd`b0VPz#CY=g<@7Fz zlD1jy#@A4g?ywo@-h9^eARv7?zST<|N-+ztF@MllT~#GokH0QcseEZ!nGRdr zC_C(>>|{q3YE79WPQ!{jUy__m5=|w1VdOH`WNFL-0$B z;HCz4cRRq+65NO8I3T?w8Gb~j186n7BpZHrx(Qyp!=ytlD;gS*VMwBix9 zF$;0FH`_14@j)#{ajPpw+y>bnOFi`VSz5^wR)K)(dDZm*(Mv(P|0}X=to#v-EF1B{ z#)NEkDGSmf^XEv$V{B@X8Gm<6z89WdE5$2ZZgD*%^s_dAtt|1f(T+{Voj@xnpG`O% zZc`YH9D9xD*^*ciG4HuX17wg@F2CECa&R)PWy9UFGg5VH1{*}xo~}I+uBK%ljvV&C)v9`|k*yXlX?R2gWSfSC@AQA5ulY?#Jwwr4&!tK|H|7+NpCSO`98mgYPfxTe3w)EB%r5{yrhv>q;i zYfzr-AKcv1bYmb^`+-@Pf+qAmI_%K<+NY5@yKUza2{I^-fgfd?QTkJG=D@PC*4_ld z*L&hmLRnowQ1fq&4oY+x@p6L73u2?Aso%^iXL?N2<~cmHMG|rLaC92huMCrpww$)v z7h$GLdFdAi-dvv!U^Q*Dx*v5c8@T(>?aVN=Z#w<-)PDc^E(TT7GqyO;PkiPW4LZzA zrkG$STgu2Yb&k&Us$kteoKEtiyzB?I`>8`bhcLcm{7QTqiD8tD@Vy;>|AnRF!+|PX z9O}jS2eh-@IjvA8YQ%{X0s%e+NH!QL1Q@CJn7BTuViuN6V5%1elxHU+UsPlU#UVEA zBczmi>KPLptn65^evScs$_A7!qQV)a6TB3K##LY67!aKmAA7Klw}7?JYR+^~86wdW z-8O`3Z>$rHRJUgf=zeu^%jLb8fDY+-0i!(!T!Jz~KUVtX$Iq5t-%$muUULv_ps}R% z9Lgap?U!H(uR3~%3wxDJfh!m`5Mw8B=gd>4+I|%1t{Er7{AAGmK}N6K)dLZ_7S!{K z^$oawB$(k7^z@@RjN+!rF3WYrK#8(xP`5=YJ^_C zV)tsNNqi_Xi^A+G6CH92A-KwKi5vgE3EpN23(-a5`*A}ecBi_^U7uw0(+ z=*`ny%`lJ89lQ-Q&eS)Nx;!~Ly?;&vumoSU$y zyaDG;_0WoT)m#sUAdN5L#{A^op-eC-VoDl!f8N*H^5dGdcxtI+-XnOvBaj42PUzYX zjBlEs0-LEHSPPsJz!`Al(aGg*qEY>^j8^rIg`(k)`v7BxFUgXYc^@|%4xhu$xA`Z!ktwoto=#g#Cayd8v%>p_ z46s4#l8D0C?_}|8bLzq7hU%I8U7uA@TGe9AV$*7?E4MA7Op9%F$V`f~`#~&dDTYj^ znub$R6{C7_)E$6B5Fkb zbLMwbWbY=N5UE6Kk0tLq;+A8ddI4sVwjVdBNYFeyeVLfNr>1*>F z(`595Y0876NwR78Tls@%D*tIBycJGk%ZqjG3*@E~*@e@6!m+68D8wv9W189_5MC12 zWipiRldI}zu^QK9d8^~pqibats1XiDfWv@ka5W{8KN8=_&kkxH7|^VX!r8M-P(}E( z9MLNOqY4=lOxz}qX%KKS5vuH_QC%5g@2nAvmrrXdiz%dm<}l`akQH+@4f;um^VpYH zR4~M7aIRoO`lY*YrI6w+i|nMJEUJ(s+W$*gl0&6|Wg}BWeY8ypcTCA34M`$5&4Qj0 z+@X#J{iMd>IVY|0qxRc1Z#E*b>t?JgrB*W(R}hxP7BWDKll^}w_RWm_@8-UKTQw^P z)68NF=_jYm?rY8>1SV`LRQ;Nfs{}1`9_O$sG155@X5fF}M~75IQ;?Mr`oAhucd$j# z7Za2P_y+gQqv!RIibblS7?C;glu^o4>5>Db+`OFqrFBY{L)9TCAHqj)(|xx<8H;y1 z>`ixhdAf!+W%<%+0O{TQuFEBb*+tu3a|}N|QfJ!<9I}a8z`2pRe_S~rU@dUjSq@E>DlCvuHb#imhEZuc+l*5p9Lg0f=`vB@5V}$ zvGB0zT{<{Va?W?|8;>*dv-WrHd-3x~E2WnEmB?w@MZ~Qc$!Je*w|u8DaLI*6b~mKb z%bo-*LUb>Ju9;nv^P?N06@)ZTt{`Pvgmn1R^2gz9uM5Si`f8NWx-^joPvE6kapKeRgr}}@iY0WmrH63-^w<~%lV$v z-IaIg%fbsL`@9G>V2HYa+{2mf#&lydp7wMKquax+%|Bi^dC9FURkxEt&lWXS(PZ04 zJoqZ*fSIgw`yS+@eASJ=2)C^DaYm%W%iXdC6M$W#PUq}pe_LOP38+<3O}@$zx9D;o z&{*Eay|i0V;&Y-kNy_^uILC0`V6>7V6@`~n&34TQS2?N|m7$63c|0gH1s*mPq2 zvOXmmm?Y)WIxuunxP{En&O3Io@rtz*v_*E~SHnE3_5A`ZD0j43N=+!Af0Rf9v1z&hkIY?G#+<@Lkb zGdzBBTXIJIX2|EU12Q#%)@y@YYZ-D}5IRB)1`UVu>NO;sXE9$oKs}-#KaC<8!!S3w z8M8l+4~@zky$P5KO7MSuSa|_XR^lM2e$HnXWHiiG(Qw&4c3yS1z8Fo%>+~~*5Xvup z@T7OP1&1BurI?Nk=u2-BG`!>XC%=bLVrqRxm8~@|!gqYbwMLiAwQ7~$EcjZHBlLQN zYpd_$5y^K95x5-4@#)a&N{$>7u5Z*Fq%BXZLTtZ-Z6UNicw;Oha>)!jiH6HAu1JmX z8ZEr$sS4rVWx&h>+4y$mDHYf^u%1WaI)>s4--sikC4NkrtvB`dJG2u7eX zWB3+_;B7S>mRvj;cn;doxr(HRCg8Q&C)&V*x4C!2D!t<`dv;beX+R6g^C7MA@3{5i3{3@*fxM9M)=$uXQ6>4Fy?vSDk z?U!js>G_t7)jG9K<(Qq)6*re*N17ZzZsKU@r0#^J&Fc(-{s7?Y&$KKj@`4g-k4Z(z zU=EveZeZOZTV8AZblOHZOkKnNn1}|*5nyVoTv*~Fj;M3m795MigVZ1~ z-u&jH^~jj8o;=ggbQVC5-b6IbX=J*<)q!I{O2@5nDNVM$w=3?<36{nVjLSM_PGY-c zDt_NQVN`?tC9XG4PTzoB!W@eVU1|p}r zxHMBR^82*nRDvg1||C$v_4#QuH^Ba%=U zo981wlq!>Ssz;=;>uCvcTN>C4&Mzyz@$B16SkJ}#Jf=~6R(4Z{vwH3-UOmsYpqpjzVFTEn!;)ynk6QTFi9=SAo+DYLwPB>}(siI|1Ex%{i@TuSJoACW4XWJ+NK#J%V-^Uy$nYEVno39(5`W zOg_62>dxhScSNZ9Qda0!>or$o*3UrS>A^rLFPaC>^PRnsG2`#@($OPjUOZ`iRXNT~ zYVySC=<)NPYNSL_lOjgd0;f5vr!#91O0V9k9cblFb3X8U0an`lO1;`CZN0+h0lh+3 zJl$n|nc+b#W-lAhcLGBE&)}VCm3IgFYTDqrL4D6Q-RFQ$7G5%17bn%C$Qj4yW#f5` z^OpH#C(2mm@aSdu#+P>NY&My~rC~DmJ#*!RMQ$PEa62@8V>zBbytasYEn1Xzp~J8u zFR@{2C@D=Ix6GQ#F4)9&KK{UArCa%0Nd6i%EUor2$>+_`R-ts$YbqQDJfO>E!pz?N zg@xyHV4YQa{tlSaGWB`(pBs8Iu87lRqXT8g(x;(cw7x8(T=G9`!u`q@NyG;CI z>Z(Zp_qTdG;qEEeag=zKVKgVQNs?Dt{*_sOB3C_DUbjzI3$3lLPAbwavM#`&)>!*+ z@iy$nZmVLmMQb|weWvUQ_6F+P{l@MdCWrE}GwJNn=gLXev@(Y3OHYCnAUJY`RjKG1 zXOnLKV`)pZz6r-uw3|$W)_nM@{b^y;M>-`}m6{vQ6L(^k& zQ8JIs+L)FGwQ&eW4onb3aFMgPP+F^fh66QSzp>Au1XKQN6I+`2| zuaH)m;YTk4lXxcQU&R(v`l?Im{mf9b=V|6+!;QtwZ)AzaF|DSxQ4Ua6GJ zGY7&Fde!d@w7IxC*~6e>v3^mV)Mul`ePYE7Qxdq2LqM_?x%yQPS}m4EtZ{ym zyE^wg9+vdP@|(e@UA}a-BPIi?mX(6!UraN*i5A1burBTsg2T)MGHj~FVebXVZgke& zvX4&>fq}ueo#|XVpPsbjVwYp)h7acuH$Pm(ya{?mUWaSV?37r;38obCsji$fYxX#s z2;Dh}CRlE|bKxbgQx#nk>;|QfH*!tN?!#m=#8m>Q3JV}}mY){biPDph70@+sYER3z=4NRn(VSGA6Exa50 zoEJH}Rr>}_bQZT{=_BO96(bR_oZg1vhS836FIO4&knGSnseW5_0<&Q5ys%*Iu0IqJ zq?^BkC9rs|jJz;?!fV{)GD25&Z?dhtottIEO2^DkCOY376eZj2&~MV9ye*wME<@Mb za~VIN^~`2@By15JDWh8${&o_W^V3xx$E^CC8?nPUcjP1$ld;jLU1fL#klss@zu)0 z8t9p)0h}o8z=>XV-gB&9K9Gz}6gwD!MFw!tt+p;$2t#!(Z$Zco3awI{MKVrHiWMo& zjSg@%6*28ywyd&k$2(+Q_*(E>i1G1t12VuSyiBDsL;v#QSV9o>%q*hsBYmC5y?pX_ zsh`{i5j&))g(O?i{9or0QHjrXBjbpGZ*UX5RST;K-9-uqbQ!+`wb>Cr-XW(Q!JEgG zpRE0IborqDrGw}j{4d9_EUg!R+0S+s3q)<9#NvXInkvya%QfFU1v=i;r(Pw*v!mVc z&_=*RLb=B*FiiS%tI2s@^vv=csKRGGiFZv#mh?cbjQB30Y>5H^>p4S-Z&+`fsde}e zv)NVQti3xS59t+UMDnBQH7z-9+3PY)R5BwIqmjIHObkmWU=>|CXrSUi9&KuP?;nrZ z6wNc_tG=gK!CA>6ak0qBE^EOK5tMz$=06#s$j*~WP6T~W9m7@yWlKbe*b5zm9_fMGt}%0{0udDqE$c{!)(xGD@=AH+k_A6~(-x4|jfCLO7bWENN6-fDi@ z7i`4P~rNy|#CYx3#O>CQpRvjht)-qbI0Hz`Sm|tv-iQrtJYEY%`(^MyC zoDoNUXD;msLMBLI&=zBjNSb(Ya&-A&!Ii6H1qt{8$H*Rl!%4N0G(1H><_)16(*dq` zn&@Tvv(L~n9Sh0II@|0OpzpD%5q8OGOb6ZFd4fw?Nss2xWy zwE!n+gjpPY7gwqW*~RR1Y`d$RoiKp>(~iDK&B5mqdDFP*mAgMakZG`oIN}vFGX^Bm}xZNBz@jEO+GtpT@~#6+6Zar&<(i z)M75yx4? z%V6I+y}g-f?UByAgK{vbRMgCNas&>jv5K^bv6)#mShi+4sW4C(ml@HlR$6HxC$~IOFN&xPCCoNsaz-Z88IAn?0`H{c8CCg<7M|$>68L!b2bv_Rem$@+t?c&~1q7)MNczaX^cn^*|!)t&e&+>tu z#vTN|d$k10yk5pmx=IRW-?TihOXIDi6NaCrliiDhKWe+D&uJP0-RO~2ecyZr`Am>P zX@j44J5<~=89RL4GiH^HldgQ^Ui)9d`M6eOhiK-WrpxG&xMg_2l%J=cL6dLdgrsjf zMJ1SecbeHDpRuM7g8PS?FOUXt)NuMNj^MwH1fL~gMJj6$Xa+t_+FwO{ook4^7o)bu z{$M}|f&2~Tb0DJFTcP{O>AWtGp_KP=cUxZ2KL1UK{g5 z=s;{PG0Y+7xljG|?#nCGZ|{D+1($mNxkMraL~9<+e9k&>Q{^twELX6(<9dZQ;BoUA z_IKrXZ}jn+SI%7aOM_QcAP*-8^tqnja*rYBx6+1~y!5g~X5G6k zJA$#x>tP93HXKiwC7m^N*T-p4XzSw?ylK_*d~l?(yAAOH9d=0~=IRN!)@7BK=enLN z9{+Lw;xpif?x^e72}svZ#k;}o0WbgUCP~$_!%c? zJ>b$R9NlvhD3|U1iqUb=@S)RLPR}9Nmd{e}raaZs?6IC(7*Lf0uiQ}X&UM&NW`k(E z-6V2eRT7~u2O}IDsxnev-chOT*f9oZ=Mnoz{WirS4>FvHD!4hJb4lJJfblQztSzJBadfywcp&&P-abHI*v4N_)T-pIIJ~5hYDk@lA!s>sbhM2-e-3$&8JvoSz+R1G_=$3e~Tq2)<1iqBgS! z!&nFmPO9w7kxc+8H02>`6WN|qV6>|?AZqK`)>&N2*)YbfJ-(gkXahJ7PU5U3?IV&m z#b=1(qwjB97LMS1lI-}TKu|35Q} zUd=gYYoG2@yQ+3QPua~g`!#(8XTdcT1)xz}@>HxaL8bQPq@QQ)MrAtombjodTj!Ek=2li%wg0&Vj!cM&GCWWBaK zy-9v}Fn4j@-hOE5c(pYL4UJ-H;SuO`aZuWY7UORsu%Ae7;?AddAJ(6>g<(()j_eB= zf>yllZBZyrDW19jD_NvKgq-v>v@F3`?K_4sHXe6A3pZ|z*pZ!uxit$s3q7nD_nO%# zdzE5gsqncqLheCl`4SfIokD z=?xelhrEz~1+ta_PXCCV_iktv|NW!n{!w<{eQ z2QYwXV)LG!_;vfgOfuc6?n`tc!J=>@s5fhRH;bT2TD!AJvTZjRKwl}EVZ3S1UnK1- zfXTJh>q)bfll3ujc=Y4maG(xJL}1-i|EK~+5w`k^F42qo5e7aFgU7r83%4y|QvXR3 zK5yZM5Rvcd9V2Bi6e9sAay%e`?P)nXWINhG{=61i)~g2SLiHZ-47^)tmSfL~4)m{5 zJq@#zX3xqF^!FLtn!{VFZ6x0v!ztOvJ`z=LDG05T)NJ`h+;UO0;r2gnbie;{iyOS@ z5}8wu5Gd0Dy%94<59=5c-o))HF>8_z;MvZ$9@m8k-sFC0fKSaWs&g->V~S_|7`#c4 zcEUg%A(vCfp(1(~C9)-8TD6X5)AlU_GioypAC!TSxQ|B!M$}e1!Y2Y#eHPgZ>h%~L zNN;jbruR*v_7#(V9C;Fd=al;Bp95tM-CrMs5eCBU1{+@ERTOiw_*R4+xtd8yu7 z8MPTjZGgYxQy(q2C68Vu5j|di`qP9^Ha}^a7TDx!+qO`@kTq%G@a&ViWj8T(ZOICp z(<02a%{l%SVP@11dIE!tk_0U18-ikQeQ){L}1n0s3;!eHD+$G1=ALGI!B zX=}4!=Gt0Y53tt{{<_otGt53Ta=!8yn=;T#0%2GIu(Ju{#r8Q!?enz;D6^qm42i&p zFA*$!H3l}7H1+mbk%9w}ybV%Rp*~;psDOTZeRYKVJzbdctHFmJr+7K`&;DGd-o9)?FjZ0Y`uC&Fui*~|?;PGWvVk}R?fZDucgQwKFo^a0qLA*;WM|Sg z6eXiAQdcW~8bD*-z5ApxRDX=WTQCK~D*`4BRnYcgD zjRxYj!W9zj0MrtxZk)&>870G+eKpLuJo-aIFhv>9HS1Eu1O0RBX2y(n3mg;Z=nBec zZa!ZA1W6wqGG;UpAti)Q zp{Aqs*`Po$9eS{u7bKD@p2Wirt@<_FzSi;O0_x$q31i%0K%*%aNl7J8j8r0#yJbMH zilu}gv5W!Y`c{ymNVHi1>N$>4*tr(dsyQa)w1h&3k=ki$s3(OJF{wO{Rl|(u;fJ0{ zn^>ms01fIDk-a*jX4D}SO*#+0(<@8ErdjQ6n`4vjN& zQ@_ob6u(3?%XuURtc0NCM^n^XY^s5FYG~NEG%ef9!(@1`^-Sh1Gvb@|UsX4w77{JL z4>MXZ`Q9<9{mB8-uXbpxM1}D9gm@86q3%NiYiL$M3DD2; zl<lcn6h(F=}B{{QZ1!SGczoXuT7?V<^+{dA>PcMp0 zNGVyO(>$)%hZ?)M8WA>QKy!URDm#H__SnDgTG>NdQ)fGc523QueIREefVEQt= z8j*4nFa6T15r3ZwDF>xWb@!+l3>VbAQLXBJ*(5~YP%nZr+bKRIeu=siUAo!f3JD?|E3rAU*Ol@<7?dp(=es|zwk7#V@=HcU(VjYb!CJ$Mk5OvNFg;z_fiKO5Ev}ma zmEVlF_+u|L77>b{Q;O^#f@y3j*;M2H9Zu@(F%jn>Xc z1<^JlIe~kz(l%>G&&yzJyL(qF7O5k*(Jr%xO?7}R(PlHarjw3g%*lsXDiioo`7|z| z^Jy46XMP&RNN+zZ|5CiY!-g?GUIjY?~|Gm9!PcSOdgbqJfxTrSZs%feMiB74j$6*5sSz`>cr;b6CWza)0A<;zp9t z5J^5YQCejFn4O<1OYDppQL+bFt54?xdcT?pi3qo+4=J>8bS;Iv+(bh{BRj#Y_)R%{ zsrFu`7GgXf23jhQ6CKh*17n3+fTsytFiq)?wvUIV6iy? zn6BktPx?zuo|n-0K>P&)X(Tn0>lZ-eh`steKm5{Q(= z%Y0N_D!RzA`H`}qr0#9b(X_dI{c>X0Gh+Gp0R5={kl2L;&W@}ZceD;maw7(%;3Mvn z=kWI_%)w%C;y$bBGI{bc{ODavr+Co~12>hTnzj`R(X-vq`Z>OA`MO^p)|?+K%hYA^ z#YHo|Op^@R#hgES7w^58O_Xon`(rvj4jn)o@Se@BxQpZCL8UaV(URSYhXs}xTWZ)v zQeoP-+qQ_aa>i*Gg_yZ%V48VbBt-@3jVag^o!arh?SC$Ys|gTZ7qwtQ#Iiz!^8*kFTnyUEWUMT?azI z3A^!{1jgt5eEL2BR@jYu9cUf_piI9Wt9*DZ2Id7Q)A*b}%iy73&pUf)7(e;^`uKA4 z&KHGU`ol|YF9Ue;pf?){0f&GR;*Y<^3mGs#Cn&%%^YUB4e?1BNApAb-oh)FixBft1 zhPMeD!#ypJ9KwB@$bp5Uu-k#Q!|Rj~aQrVXUT168?cWKgepJ#4S{qE<02-N?;oUoE zq-n&S`F-{?9c6Q5u&l+>lelHHx`IDleKQwCWFoz`szxhrSsm8kdUv%U?g+lZWI^yZ zaQ6pPVYkJMPS6Pqu*EZWI&wIoEZJ^X+gyB3r;8r-(k&t*`h$ctAj)aas zS&?~%|40fbbI*6L?gHr_KD-YtK$U5U_?#b%qFB&%22i}mle6GL%XCTDDBLt-S7jwO zDvbl=!dE}|-e|NNCxRFnC!p;YPo%+7b@-He^Qx=dGsygqDmNB_Iiiz4b^(eDwV1iR?QPFMtXAr?a#9nL8aTSeQFsCUe?+2zbL9{4=eGvJ}mi>TW|fFV%0Bw%|~CA(~;QOh12j6(M0t zf!F|p7G#YT6-t5-EqlygEa?5qfQ?M@>MwrC;ofqfj>h;RD}$AVo8RY#&AnB#8`g?P z%G7_zTlDq1esP<;ym7pKD+<<`8zdu{Yb?WrSC^cseK z{n@_Uo-{i$HSiC~7=M1efTFj47QClHU&elETB|_;%UY{;#0K(qr6y>J=XI9#OQSb` zCg6~57nwv{;E-!aS1%VRO!cDzmpH|U<&spmpn^Vk@mOLBwpMC~P))vI zBF(OG584m)G!}uBiDY{aE6oc)XeYiEXsh+wHZYj7|?dfS_-rUs0qjs7Zimx|lQ^5liX zj~4*B?NPl@Mzk(4#l!>I_}*Q)3#hZCS}PsihmSU1L$41^ji0v#c*DnZ z#PQ7})lx?%^!iA$9l|pe2||v(OQz4uChj}OcfY`^->(`QS|k|8XLj3!ZyU(1 z9|omrvU|opoNP~xoWGb}bP>s)#x<}(ej~jffB#~6LHyqC96wL>vIo^ku1buk&+ypc z&{GxeVg{IAGhbI~p&SC038Wwno_2(_djOUfo7YnEhek~(LWu2-z7YnJS^b!h*w-iMwZA`4P#zE&;1nSCU&RZ!F>y>WFb^O6 ztMGqE^7qK6-1~el!@mrBX+2x0xVW8N2k9fQDVzbRoyB)Az^6cY4_~Z$_E0QdQR7%$w;mx$lyH0%J+qm%O}o?yUali z*bL98jm9DxfmV(OJ5t+X*sOv-pdy^X0&y!&L0`wfHo1C$)^y{ZH2aJf!w?XmRvnac zsEOYJiyKh7m-pGzHA;NeEwB}~<*Pdx+KtD(serZd?p??Df^ODc4T_t->Mohz)5c8+ zinJ`P1ZSPcRoy;kEtPtGfTL{!VaxvF5s&Sm2?{2Sq_p9;Y0{A*h4K4Er%0B@)`_Ad zFMqb7flOuzv7>|u;01!DQw!FOMo}G>=W%Efa+Bzd<M)fduG`iCt#`}+){6&KPG)xnDk2~PErWUo=>_uZgSOd6Wt-6VSG6Qf;c0S1 zvSW7^Mot7gAcysM`F*yLL42##2WOYw`}jN`n~s1>_qJ$O72td`aI{a%sP2AS2yo$Y z*eEh@6eHAAxc*3WSqgfIi^upb`DD$+L@YjKzXRTVQRMH^aPuuCDc2QN3Ka0?7?!K2 z#;#!+aGfu@@#+54MYO0$>prvw(XCnT4i`!x+VOfJkmF2JBU^v_cWHEc#5$Qt2}wn@ zph)*U!dShGfPCiuiuSFN3bi7dx#IlM^O6QN+5zzF_=`a4+^^9`)9d+;-8D-A+&%PyXl!Z>X|1n*%W&PF*4%t5mH3U~`|AmDPx(Qt=ayxCsDPB_Iids>e6Uc;CwfQlOE$$Nv8X7UT zOJMYP@>|B{(!Y;unzFH+5AxEV;sB1_&EepM8PoiiAcA zvsb9kDebA;a316ctzbXCK1rO zZ|an*)_AI5pF*`-O?*_4|McRK!E`!p5Gxysb9Mjn{l>*HO0lYaGtk=c=k6+n;qUkQ z3nnGVIQXj8qrt?-94QSFZKxC1vw1_#Dh;Hf&Z&c}ELGtgUBZxX2$QTz{*PB%&JTvm zPnqz84aNLdnto~@)==7u@6jwJ7|_hfTAnJ4MxA{cOk}=bLATHO=!Vx+ao-V>1gk58 zVy;Nbj6Sk(+7#m0lsY;CAX;Ly8qCg!6%Jg%Ebg+gHEf4#v1%nX%igqRw1r<$71>?u z(&J2_z7YaTfF;1u;~Mjhen&@sXv35HL}(6#s0fdwAR{jzgM9n`4Cqf>9ao*Bz?3Iv zQGE`2s$s2Mio=$jYg^>sq1-PKb-5^`<{N8T3rWghDy0}%ZlN>YQ zr8h7$>8012sw7!9qEF&sr_C@PmR(iJnBHTztB;9`bnBBb82P6xm#-&4yYRh9gov z9&URa`%-slBioa1P9{FocZ^HUVwg`QH+!eDCSL6;;xIT`{g!Y%AT77)p)^q4C1)5r zA6GxCsHetC2f3eV^}gO)KUFB5F=3>gbqMdWUbWvfJVoH@4)~MJdO1*Chk|A%nQo{4 zJXP?}!--Spy9xeq#&vs`Ql`_kCx)*K-GFWI3Md(4Qf_zLUAH12P9KUvDhIwj@>~Al zgB;C?eFVmVb9}`23ylR&Ot+Px!nqT3H@uSYWRbuOyT@&@!a zWq6G@WqLEaosq=k_?p7v#fz1CGYii0c1k@Sx0dD{VTso6F19~j)10pbnZxYIOZ_<4 z91yoL$qqQORoj-+72V|Qbq~A$e9iL)zhS-(z-80Xy&n*?fyWsd$R;$ItgX zS3U=zbFdXS`dpO+hXME*#dIoau+WOP?}qsKMj9siz{k8gr- z)rk`HvqGXbLjgu);)3#A-Z~W{(gq7kU|c?$-o2JT_vGoAYPm^xey-BBKb)IjDeS!g z9x@udW?`6Ev|bljA8Z5;K9{gZ*u&>r7V6so8a4%2>mlDT|F{d{L`3W#xba!EA!zV& zialOaha=(A$fVdw59}?E?z~A=afCe*9@E4Sx$&Xv^LXd=#e+hsBA>%-z^$f6s^hiXB%-|V9=aRXElBD55ld)(A07vv?F3JWd4qeXO@>ce~ zp-&E8SaM0#k2KWuaB1ZPR+DWa{z{)ae0HLQ`1BReIDR37%EH36JRHr7`{t*c(k<3R z5rlQ=;MRFDPgiES=!4MXq8Y5`(~n7)2B;KOJR5My98R<%u3}p}Rw`qaF7%d(%O3wF zZN1;8${63dbs^nscv_AXD9kiMm+T94C%YO=-sHS8k<*YHoV*WfyD7**C(c6uJT>~m zIb8xWUrN}WcMlQweN;J|B@Y_p+Vmq#?Oyazc=B2Rdi5`VH1+g!+dbCml17ZzO>awgXesY|@4jhS5idwizFJ z5dR?!Lm-~C+iD;XYrMe=!2%123o`NoU*Ii&NyEj)j6E)#X?3{}smcWssm8PV=2ek@ z09!sJ$Uz#{9GYq@B-I)4?T=%ZK3-MHw$raUz#g(mM$4IuGAfAfbhG8e3uoJ^4!~v2 zxk{OB5&rVIu1aZTA5KvO;l(jGqga3gf#y9E(!)>`59kk8a!4d79O6s zGX4XTv`D*+o8@OxWk58l z{(=Mc`%Deo2AVbo1jS=4$W8abK}&}YlCknLKDV&fveb9A-ADd9-yw2sun&B2pT7NB zhtj}bzKR>4M{~%R_UUF~XE)JQanu4Ohgvf2;WEtQvN%xr25pT3pVSDUNhfBFXK zuqBatRDI%c(MT0Xw0IrEVWB&g87{-Agtom2dBMqjTM?vM%DoLC&z<`a$P`EV9zX4h z1>Q9EQ!UvSNwW94wJGmt7HDG_V&CDam=LSjj9U-u#YCWqxJydK1{ld5SX8G&a+-16 z4AUd3j;lK-78 z^t@qw@=#nn$U&x2kV{iKP9lAhgK~iPg;E{cMD2j>t27!xpd~s#{jEZ94@;;uw~0Z| zcppC=&D2Y9qma`O67MAk4wCBU5-NZwkt_$njN$tM)MQRN$WlO zP>+AN?e{4}7WNt7u!~|h;b3gEbu`kG#hTlRMcP_lX~CjcS5XfoQvdV|yp4y(ez-nD ztoGYSXZZvo1x(M9*7sfl=EkdZ5|ldIQ}f2lS5lJ1`jdubOYxkmh7ywMS-kAQCXfwt#B?6k*@Eya++*S)^aII01zh9q!N5 z^YAVKb99sY4S@HCgGlS6xwXSez!XPBd#(jd53TGZrIaJehLOM1rPAq7f+3Njkhor+ zP^||)S>-5h#Way3qh~2AuKvo059Uq^=I&B_j7`uI4cI|HUnh(>UK!5DC-hXtfA~$n z)qJz2aaLOD@nFEy-9c2kURvyMRWy^}S)06M<_w!tHJ5c1p6xC0LzZ)dc!;9T`$e1p zq*HPoa@&hw$*J?!#m=UvB#IVlc5x17?}u<*WDk6!r_Ki6EV!#QiRs$N{4&r`Og?}S zPRlzk-xp={#7T_f@d>81C7(ozWcc!;FLEFJu_~@5@hpbIf7p=cM(-O1lei9)Q5GO@ z^h=T31}zlVMFs78@;Z149&5C6hOn@ZkDV42Uobv+e*3*Js2&Oi zQ4TPj)c2SLXxa%){QS*evAyEU^gt<-n%MPItD{P?W=*VH)n>?oEewGNW)3Gr&T5FZ zZ~wuG4nRk<-klyKFAI=C{@z_b;Bn)7zCqB-UO%SUM&p!d!P44XXq&KtY)D)`nS1v< zf6N}(jSZtphsyd`ZGGRDn#(1Wsbk`Z$4ZCuPY9@m>Q(l4-6hoh7Uk=%2C8ZI@}r;- z$`jDp-ESe3f4%(&qZx*yoe9a<@NWfP@#NodOnQCdN%I7g_NLqQox1AmVZpY3M9TQh z3J&v+W(o2Cjm^}&ws14}-vwt9PW%H30{~}|-I%Uy#t@!N!F0Q;wH2576)vf@`9hMz zrSu$s96*ll&%#$w&7~hv8NRjzDK!t_XhME?Jgoh89>eTF#;mV<%$v&uZX(DsgnY^a zY=MiYHa_C+7OzbDJ4Yh-8%Vas3G1eJT@)W73T=5tJy)BZASKb)EibM%=fl_6#YJ>&q%Ds*fo5|ci4L^slHZQHWaR$q0|9se z;9urxAxaq2bHerHs_KlyCWvi-#)s|8Uf|?mBwr$HX%|i=1a+2Iz`l1|sO9PG2=HHu z)NwY~x493xAo{eL#@H}2+=$CUpp5; zxFl24*{(aB(c$ZD^&|VSJ$>%XZ;fGw-M9C7ujy{*geOhE4~d6$R{YXKh_Vv%=r<4e zOa1Tl2m{yy@rGRLgS9~^f>-BOZ&z;jDpIQji|-@v_;>1YFZ%>yX!p#m`OU)3zBb_= z^ZdsS0NvqGji2auUB)3ghJP~z=Dr-qFH0sdh32q~UTR^ZEc{UCZ$7fdP2i$(JO1o^ zyFFD}8rk}^(~fpz(1IT~A4Wx!nk_pz$wq0n)+c#8-r4>iBLG|kF(T(OOC(HAEa4|_ zt@c)UEx62(YLydyb(Dp=f+wRyzLVS6Ecx1KS+vx?MMLrXB+&3c*DzW4H#wy9FF6zu z`yV+ps24o7wa@tvIpluymmKQl{9nnTJ5o8UJtFmp!;kUe=DFudn=F~rt}!55xQ(2V z>dp^|_Xnb-NU5r-VYrKV*LvwPOrcF0uoQ4wraUyv9!pqlqoy=E=E{y4x8AP zV7RTwWac7iQP*BP2*~4Qq6Wz0g`qWvDlsQT?J|F51_8+9mCJbwQDoft^vB)dt_-l&>TJG~tS{_4WC{97W+NFD@N zS=8NB(((L2;;vpPcTe@+;rIJ&(M(VWb2*6%LJL-u^_%Q?o0$E{^T3+zJIDB+IBrQ) zLS7ADm&`}yk;*5cQQ*H;t2GmrMdb_&_=&{pNYAM9ou)dZBz0}>=pbN;3^cwNZryDU z0JBYF{Xb?~+y&nQAYq5xqDm>-(+0F6c|Rq(#b_Yk*Q?dOB%15COnpYLJ{2xEQq?X{ zSh0i&4E5PO?63vRl}}PP0RjCKNdD(CwAdw{=6m;w9|t~b9n<#Sq^eb!PF-4lY0Fk$ z(aP+O<>2&r9{r(1;sg6jc2}udU8r2$e~XoTCVdIxaM}1;P}u8;_^VJl8$hyt=f$`D9fI-We}KX}r0#rvK&A8VFw9l<1v*T=g%#e@iKKvlRnb;+Qs` zFu1q0pw=%VCNTQ_&3XWq$dhTq0c4HBM1Qs2-Yke8pa6U*;OF)Z2HM*AUkjfjL)u(T zt-VFiddyI<7+dqz;vDIxNW&HhXaD44Sz{v=>Oq>mknLbY`fAY~@&RGW!9TV{Q|0B* zz{Y|3l(b*h_H>0sxU^rfwBMs;hA``jam*jimnZ(?%)vsuY0G(YGI~1B%drvt2$oif zZF@`kA5GJ!WIUV5c%^X8zP)B2!e=JnoI`Fy6~Cn_KAk^(x(yA}zT!DMmpB50#$(Q; z&7nutz9Q*kIeJ$qm6VJT0gZ-l1b{7x7m&+oU%js!QR+CL8yf&AmIAy2oE<9(7n?gUl92GmV-x7_ z)>I^0-EumC&~ATkqc&exDO!GDcaz%R0=WIYO@J<_iZStjo5%&cX6}w;*3|&f+ALI- zc(+f7NkN8Z{xlpz|Lw&403G%(d$)1sf;)+}UZt7c!YT-Xu>ScBKKvN z`s&9IOmHs>W|SAkE9A$>`nti6NR4zQPzrf`FA8C4_UFwK~fy;pm}Zg!BV7m7Q8Gishgw$Nc_0@m#&SK zMWb4WVpfD|7bV#N#~(K~nkR&Ark4#yu!caFt78v7JZA?~1oymGD%OWRm5wf`#pGF; zL6xAVQx6+rP!WNxJ=#V$^tTRf;Z~qhtrSj{fgMIb_hzl<#ON-}#zSs90OFCAH{uaL zh9&&lgS(lHcy_TsrVIv#GZmeDiT&m%Y4RK0HdM$K<&&;&R48uc9UxEd*wo89K>obF zK3?pv()DN++&&79O5ptyaEEjpW|zsWz7!YiQcHm&Jo1XTu)9*RqIP9Di({Z>V#G ztsCvetORYUAi6riwsr`{w(di_&>35|_?i+wIl2fMpQFi#QRPAj_m>@BCAaHpbhXN;OLQ?znHn)$nE<-AT_0u;`7V(HQWUA9;; z`(<43|46;CcS|y0wWCbH53S><;bMvD-!a;r36~Xl~sj=2^O>F`@{2%8p?#S)?DZ@-OZ|^~ z8UFs&y?m>~e*)bHE7F|K+Mt1@j!r%o^AHt>P!Ic0?UHWTUAK3*XqMwzMn0Q;YCbzY z*f~;(=I8>xE<}3Tw~VXM#30Mb>B!DGY0)3|)g`^Nx|nNTy}pdkB_Ah2#?|do5ImVb zC`&5vtN+!f{H8+kT-o^?5c!=E#XM5$bG=-1vzU`AO=vxY=@ht=Hs{!XSd0+-3in2GRNzBH ze-`adcOJ=F*3o#&3E2+{9rGwwk&ZY=s%JCL0K$w*h%P2{?=1V(YA{s^AY6?16ObT9 zbAq%m)O5DUVs&oPW1~sBkVCDJ*YZ1&1U|B$C*A8}rVvJik^XuzoIEb_Y@V^wstN)v zt}<*pz0a!a*KVZASqPUU$&2+fiVsL(FCKkLq zO%9MN)|DC~2Q+jW2P(qIlVpu*+5c14Ke-z^QO`rEX!uE=u=$eLCN>vN1zND!A8SVS z$N&UI`>zB=J8NkS=SdSwZL}BP5TDYwLs}H2iBz=~eR+A50XD)z)3EM28?W{HMGy zbjjPRk;8as0k{zOK#) zlo^>9&BWpO-OeHaokhu)a37@~|5aUC#}?%o>A8_>$3#KsU=3^a*s2vMsVaDT$lfax zr!n2*fZT;4dsyt!SRyrc4Zh1#QHsa% z3%pd~`W&YHM8mCG&(?*}Cus9v4I0B~!P)kz^)Azr>Dx?47LH%0$F&pkHoyfKP0!19 zd`Y$Pa~u$BTRs-EpleGw5^5 zJz(?RflMvETn%mRboxL!I|ZT7)-ax-P3%CCGk>X{v7vHdv1kx|zKC7!#tAP){e0=D z&N1GEu&Gz2x6VO!^ZrnSvYEDqR!a*=ExtS&E!lndfX@hr^?r2Df0)zUpj**UT>15% zxxpW*t2du?S+q0XZv?gY>mom0GP=KbMP3x4%0?MLN3Xr9#gkF^7Z1+%yJZEu{%>+7 zt3;mvR3YT*^zQ)WLF3^lnBU8XYte@lptb(jN}WY_na@$RpA8B6wy#d6I8D0a2I{3l z6=LRkc>NyA&jmS$gGDn5DuWHui^?mEbBcELawrPaE>0J;T09@Gj!T!ZrVU$Ws{#zq zzA!~%l!Dl?x8UXv`EF@x(A_$r99B%-ZBuNR0YHrj-L=^2b_>ka!G+29-BxmarjfrU ze?G2qP7rdYT(;HUxQuJuwZZi3=;$0;UD_GFZqUm+fbq348zJke8v$&^4PGr>!5Tdw5tnFyVp%ttH$K_GU z1b1mcJUIbtwS=~PT?pMz;i_VzAuC|`Ma6ZmI56@l{S_G2Eh21ebFqh;? zfS|3KYsaXaZWCemhQf^hOga~XM)QV@!_h_y0zZ!9|2ZleJ92J17%AJR6_Hto_)paB zJHndAEaTV=RMrcvukKVqLR0(Eq>`RQUb^w=Sbw6i%6J<4KK@5@zeC|~Ni`s7$C%c?n)b#a*ln%*ri=sSU3 zU73IxAwq$kPZ%^((=<|iCU?KicZjhUJJPa094~kUpT~Eo+1lpMv9ka0`*ss6FqCuY zVb<%kM~O9Ou9~2y;=anjp5EM1b&1;iar~%x*HEe1!SN=yc7t$w9&6|g!hvR=2#yua zQrG5aSlkfOs(Zp3nG+#r#o*D3HUa6H3&r&?3QLJm1wnD?xRLryPg%g<*j+zkZ<1TX zQ`gd2ZeF@OWX{Df&BUbRR2bARA)K+T#_pJAyYW9RkWA5P1S(T)@|HjjNTf_;l0N;# za58lO-l5St5gMbTcOhzX=hKDYlzL#L6Y?Yx;OU2b<8>Nl-#pQMpJEAQPQHfBTI~Ai zIN0_Q@8?owPm|$2|s-NiikXpj5xHyD*hUc5LpMDLMFxIu0 z|IIP;X(T4a9x74f&S37th82ou@`|L}vHQ4*R*ipOD>+%`770E6JvR^7+_ky2<^# z$_|x3V|LAKM%JaIsRf#sE2t0EvZLSPk}J|M?T)pcWm7;v$V3DQYY5C%Vw91zoXnylSGJP=?PW<2A8bKRc z|8L&PBi7`}+tAnSou#blXa+h3jGI{ZM`!46zwhjUCaZ6Qz;*I<8*630TAWqYgH z1Vv1Pq18oGRCwbTTCticIIdP5tZ!|zvD~6^Bx-#UQDWI@e6EFJL&+A}41%KVRi(Oq z#tzjk?pn0)h+SJ$e+^0k>8Vl>?G*=c9*jAv&%2DkzRKY|3^^POhO0>5U?L!Ap#RB> z9sET;nxi9Xw)}sft*m==s|T=Fk~d?h+A~4I&>dcTgvK~yu8e*l6D8~cof*M)T-v$v zC1W~}EE(@)N?PDh&(2k`?queP2Ujg*uT&H{w%d@{E?QbpP?T)!a2zhG6NR6Do-Qjy z%IPYqH!HD?ePk57$1N+|uA_|GS}c#+L<`j<-dH2EYhzl0t9;?6444COQzq)h71%C1 zIw=h%gm*W}KNwRVbTL_#?dQa;W`>4NL<)G~)a5E9>M9PmU|=78_%U?CPmQ=#gKX;f zfJm5`BrJ(J#37<$YVqLHS0_zxA3uxnOuBMA@9=XO<_Rq)jC2t($u`Q5T)HrLiv2P- ziu7bC|AR#F6<*jb*9X1y-}2r|$@1RuH-2RG{)L0lsKc^_6ZBsQhh1<3DErA-BIRl8 zYYU5#9Q+$a9gvhr=+z0-x0H@aw+yvJh;wlzS%?oPqf~K{$zZ%^IMUVrL+PUIJ@B&ax0 z%dzFfAC%VRvj;jzYZi{V$ciu*Fgj}tuIZJQcZ!x#`!H^(WptYkLB z>FXzH%@rX%hko2VD5E>Xq%PwC)bvPhncn;wbD_gs!x^+*G&7PX7tvjr% ztTwn0++a>mXeg>$XU#vub&fR?bScnUOgJKjVU**ZjTcSRv0-g z2Sii9k`_qjg+MC1TKx_)5_E$`f|O4WwidEE+&URdjr^<`&0EF9y8Ed@l#*eo;q*4f za-DtIv5xt*s)Z;Rah{Lc^ zZKZ!@P&1SAP6f4pZX1`YQ+62e$YX!XSAa?Ag5~=ZAwap1jdK+mXajCQeurBvTYAtz z&PBNznqK(f!S^^3|0J^AV#Xh2Yer z83K)VVBMUt5kJ$rJNN5OeiS%ri&Th&nygZ7&}jXXrD!&b^E^BjZR+UXTp)=$lIoY6 zje*p%H4h(X4!e-&Ui8kbx2A&TZV&(v;X49ih z_)sCoKIXFVT-|Ji@@0$G!svB@=Oarx&~U#8(31`H?qn)D#Z5@}uVhBj!mQKu@3;2M z#&uV@5NBSN*d%NHPTZU}6r428lvJCD6NI}ao~912*6at@Kh=^~ReM^@airFA`ydP0 zF%i`Q8h6Yu*1DWyLb(!eCK65B(2p;;ym8%^Z$^JNo7t-uNg51q{RYNrX~?c-bCK=8 zoEo9zY?^=CO0y@?56u6nV#;wJgQ}wQ>W}sm~bJwf{@8~k3FcN zug%GZ_3fRyyn}sCH^@|q>+|A-dWi>@=EinRGl>F|0ZLneObXS**c`T-eKMAc7G#2{ zE(hT`(t0qGmdI_17k8Y@=ea%uQa^ZiN(JaHAcBMzgG4s4yw<=pFhhAxKWD zUv$k_SJ(4a-)N4v&KVtzkk6b9W|B6OjdaZAdgjCc-BbLE;%Z!lU_7=6wMu$cYaMD+ zp&4qMkIjB$X7(YSmb8jYu$4iyQu{T1mN=r|Nz-MyJz^ZoWouV)yHJ@NArYc)N2V`l zGZb!)H`f%YPbU)35Hzg6)$GF-2DrjsQBOD*CCvCz3OJ^zU}>iO0yqlLKOgPOX{pqY zj4SL(9h##?i5Kk#C-EH?%`(f7aCRIsG?2M6i{BnZMx?g8Qp<`Hrcp|ZBVx;nQ=Chd z6?gX}&QU-j*=B?r@T=3|Fupg}$EnOQK5O3Ac1dNK4VvV{qR6Pc__|*P>2nMxgPXz2 zU#;~6f(B8Suv2`YNBpiK4xAo2-Ozqezlv_~CQKIzZ(g51h_K@#nggCX{Se;pTYT7D zgC24o{Nk1{@Ps_|&-Y&^qVgvSq4xCB1t?4tJm-L|RIU3SeI+-kduJD% zZu?tlHakCUEEJF8h)JArs_qMvTrHo6wPA0h&pRJN8{o4YxsR93M-{7|EM|Ys_RgOg zN9vW_g^iXFL5^Hkz355q>3Y~Pb)7s(ttTl&T~ZtI)Wm%E?97@{fWGo;R}DK|AXrYJ zRfcr`|6=SN!y|dycHf!Uwr$(CZQC{{wr$&-I1}6HXkyz=CRv&1|2*&euD$m<_WICu zSM`_fuBy9_x_;+*UiT==&q-~dr5-uLvTDnqw(T}%vQC;`9g5P#&8atKRth!0@>-Q1 zHWDjk2`Z&p9%l|Uz@NyXr8liGmizIX=GuB6MsQt9Z`gx+5kRYvYM6Lu)uYugs~lPi z8Nj359CT#$uG1DjczduNLlYt#)bC%i>_p+BlJ=w0`1$oH_)J^M+4T8+Z|<|$Bg=8nGX}W0o`rfAAm{;maC2pMFobL1L zc&-PJJNQ$+iiaLtU%FAJX8dJ@ZAQK3I=frGNSATK&t~EE@un%~L>r(IxDM%SeHGIK zkiuU48J5Cek|6hIzLp(s#s2|P#pErW-F0VN4&Zj}zG?DSA#_nwIg1*SNB|TvZyS77 zxFXo#{BtO_+wQu$a?LzvTN6umI+w#PDV3=N0@Q>wT1tg#ijCAQJ*7+R%wep^Al6hm zSZZk+Tc?gbw$c;Mdgkm#>d$(Mv9(i2Mk0q1G*Xz2&hF&Tuu_oe#a+I6GC6i! z)76``c$XbNlxqf}lW)R(@Pz`&7?t1_E`sD~Pk8ZZv|zM&cZCF2aa@pbx$G(*RcSX( zQl1ZpGhtUy9QL2P#uTz%n4X2K_x-BgxG0UvezqhFM_&38SR$m8bVx2~I?Hdw+N3EZ zw{W2>wh&g0gi4TCF1HbvacNF>U#XAm6i7E7TdRwtNtNI3ZktKxVaHWG-}Dde9mMrX z$K8{!?qGKS``i@Yg8v z+o>@>!Aj3ex%{l&Wk;W@+&115z_(cJ=}z-5=kF-fa2mB zeak~aE#QYF9{X;2c%a&gp3t2Kx*=1dFlVbcC+jYz;**F9p(3)w&Iz}kmxc&b@AG9WD?dP zZXr|atkE%|Af)hwQ+z4O=5$Xo8+>Z&uRVlJ`~)B)}~gR=p= zw4ry3M-jE!u~@0(#6ZES?n&Ycahl6r?mg{Z?hSLAE4;ufmVdb_z0q{PVvg8H(V_`0 zOtfO-UF^-K;5xY?X|d2XNlA)f{miK zIcX7TijuoIxe!G;vX)XLFXvn(oC>8dj6{SJ92zX-SP)8arleR1Iss>f=N1^LaH7hu z4#z>dIZ>p>B}&V(gT7Ers3utJ#7s*Pk?KjFT9Zh!Mx)T-JAfqV6k)P{SFF*hwl+!9 z37SdrJWVFkG7-|3P1>;ee0D?3L=Fk99_X-MEWrdKJS9mF6$k>-xMt%OnGjY-&$T!89e5}qH!9oSWLXaUycs8M2kgiCl#lZ8DVCS?J zd8{sphAPTKyvBnkI1%UxAm*Ixg2>qHsSfgMTsb6#PBOtJNkp-U;ow;t+XhXq##0Ie zve3nw$pT*U9)I#|AxQox+?E==~V>--q;G<6BEX#5S_sIZew2^(_x+}3Z6#2aKxaMahQeo2h=k5VxUdukW~0 z0PINJzw#hgb`%IcGT?XB27s((o$n^jac$lXR67wze|LjpYEF3_*>Gliy#_ol10d;cNMW|_f8hqXHo^A&hL&{bb z=(6Qnx*25#*@Q%8=^0~$*jOb@G*lKQrmU;!;K)=OMUy!{2Pw@UAGDHK&}aF*Ut7z~ zo|#bEZA!EsbT&)R^;p2rf~EB`8%9>U>#8Hj-mMdSbX}%O1oZF!e3!g`A$x%hei?%c zX|IuM7c%UDHLR@=G>q+kw}ZH&4L1}jt*)(sbJ;z;Yy6*uoC@pT zLXLTWpf6bCpF-~a$3KOfK}%bqllhzBXE{ci!f+wJ67|D4-z4uI&<6$=1$E2BU118> z(3@cuckq$SQ2W`_hT_ea1Ds*k%alU7*I~9L(v8&_l@3K=x_*lWFDT?>q7o~p5qBIS zRQsj}r%mNv7d^G()V*_H$-5rKYihRyyWdw7OK9%Tca=I&R_q@I3jy@KLAUY?X=OBG zwhH^>1DgHFg0fYhLl04cRxP1_Zmw{2E8N^ys!m;Q-Yq?}Is|tFDMTs0Oxs~VQWs@+ zc9o~|CofJu(%+@nAGlC2v0(E3{-EsC6;-xY_2h(_;s-k_b}-oVh0#7c@2(c;PGqk+ zu8S$4uyC(KCM__i&=*)qmIJMW(+>$|u|$z8n9W_>hs}!9`}H~uC^LjYm%Gr&|2FM~ zr#D-%?u=N5jrn%!C~x+OOz)P>W(sN(?;dtmvr@gRml(2FTXU=RffWXZZh=Z#_)z zJ;iAO-;{a3JjdyONb?a`3oQj#Luw*7mR>ZGNs;!G1}=}0el7}Gm_#WCSZ&_(jsFv_8j@geC7()w*%ybXih=c_Y6u+SOHu5ZA<;{ zD7vuxa|hQEL|$urUavtHHbuDBTCvBL+}IZsb0~Ajh2$dg)P>|ytKSRA-I(u-1!+Gj zrZ-R3@AqF$iWb;M;^yV${pDt6{CwW8@(_3ly@c+Ak0Ixf?V5$Zc23l0k%4I?PPj(8 zGztRu#~tx1b`wCXMMy~ICt-iSp}dihG<1RSD)xsMa&j4Wp$5}zS-8isuhMQA{fr?Q zg~(V6klD&PzsA8DqRbU`RydlaFlNma4mz5ZK@B;Yr7<)*yD6XHI4%3RW#>hms~KCg zspjkxx~#kW*}q!r3Zw@0fJ%(eK_5iF;nKLKbkU+!SVpYt!}JWZ>6^2}%n{lN zzI2O1DP0#t+<8Uw{tH}7G2mU!Lekg1xj6I%s%77;>r{SZrRoMYy5}b#amlqCR4X<< z6p@a!lEXL{szk|XT1k$VahkN$cmV0Nc_+hhDkZH_@OVmyzEZFy5NbmT@FY@ldQr7F zC1RI9DVovAoAKt!l&*_W2KEY^JW7$ENTkmX9{L?QOQCfbEtu5$rj&$>ENxx0P= z>sf!stvnzk^*Dr=0@kLzpgiDd4qE$yKk$<~BYK+;IUzmSU=a%L6RM9*0w#M%pnNft zY433ax-+113!45sQb-yhKQZ>~ zAnJ0Y7&R^|lAoJ0k*tkial#)bl+DM8$mLXVdNX#OwVE+vY0M4?cu71+yL181U^*ce z#7&h!iF>qypAaDsPzkhNQ8uo2%UGL4;;s^O5hAi6g8h;XDy0b7E$@ z!f*MyPszf&xJ(rgiHZ6kFXN=I1lJ}VnvH37H9SiW$!wtU(FRUQ6_Zpb4cC%|b9c`% zc`g@{+wZ4m*(O11@*JIAv>mL}x{#Bq>Pau=fR}KS7PL9r)4P@_RW!;9lc{))#~|}K zSrMl&gkei#t4g_+SH@~mB$cn?Z?u1%`>OJx45K)k1HQuj zcJIUyr25MxDeXoZ%oPn5qON)_a)Jg5qI6CD&Onyz)>WNYMEJ zylGj;OAn!&@Lj|q;>Z!m8;L$NQjuCZye8rV>D;bXDQ`NFNF8e3mL~Jz@R$oNq((WO z*LaY3;8WJp@<8n?o6G+IhaX`sGdTRiy*NYN?*xsa=taZTEM&h6h8NfJhj}PsDBA`h zL>AM_8R1opmHv*3#)ZQoF`N~QUms`^Gl{`aj4VSywNPDnq^4NpvZN=9CHfU%B9E%* zn8c84qN#MJw1HwA1+X0EFZi;O(;)&5Bp8IwXw*{{&)7h03?-?JU_hCz#Zy{B5%IgC67@gDUxkDXH5PY)w6FRUgqMUR=VZHK-QerF+J&y zU0mp5RHrdtT*Cd8V}Y>RdH%H;tvSyRZ20XSTG+|I(|=ec6}&VcMdfSuGp3lzY>JI_ zsmx^x02|6^!&jw7%xmspMT%1vqs{u4JE~pEQ%%6C;KFYY!zTS6GvVAoXG|iEWI?fH zm+&0>1*JoMaL{;Qcu*2336yvW0&)-%aBY{G<^nOLGu0oI#14nyECyLvlF24ibLH%01gsXn zxxP!bp)gX43hj?)0^AN13xb>1j4*ZuB_--}Nu)-7VT4%%x$q0z zO?Dw^?8ehcAe|WzB#TvJk|P?>Ixrhl6pLD-n|VI0-d?RQ7f03YJqWy8 zJBDTL^R^wrXF=>+C5yIgYA<{nG8pQ6HlT*@x;-j5G3=(? zlK>X`nb3T0nVWfEtTQ+%{CTSt`ehacKT`n~y$-?js!h4CB0Ikcy7v2qjF%85O-?Ug zIsJp{cm+Gw3iE+1Emhi-gAcO6b>p4+s#Uu&#?X+yf5AQeP zr=F+dot|L$zjaBOPQIu%-OX)-7kiy&jKh>U+*dWs*huH6hVRge%O=t`gYWzAf`1o|ILG_H z3jWOq;q;5xf2mVdH+8%pHmR)SlfM!`0Vn=Idq-W0j)7_;Lu4xs?L0NL?|Gcv=Rk!D zwd#Wus@;*s%NKZYS+`Ps;4|{`Ll#;jPeY@f&b&rSl1+ZcDI0xO1}2q3i-8HUn!DBk z34cYWO^h0s`@Y+kkjbV~bphf-EsJ1eD5fZd4lXQ26@iJ{Ng|e}Ngl?d>O)3tq>^z@ zWeX5Jb=^}v+`vXHkV{TyooP_wncN=QO3EG>Q9A94(9mn_g?QWjgB(0y=<*SCVAuES z6gtk@aVsl)*Z47(fx+_Jd}!(|mk33*9>ZRQiQ<#4a?V!UvgPrO8Pzz4<(L)n16FwCrQ{Dvw{y@SD!Cm|JJI!em6N~bzkIT>J zTA!PnKb=WCVdDHPTVDpK#TUJ1yzWj|0c73JNp~IkO_m}8n1lG}qv0$HLp|2XLxCXF zY{_Q^b`RHh({LtfGa_{#OD2(G;m%@Va7iOOHor%toaSu#nhI1pcdjCxB|9MLX0BP~ z%9#l}e-FJuI3I=k3Bm8s!`tN$fHU|YkO`$7qgC3sg0=eut%H2c_it{E)RnN-ek=S` z!=%X#$6P27@JrzRC(_+>L@*B4pQ>)1l(HlMVw1aODEg0p z9dNSyvT)t(64W2W5~pC|y#fcCye5CNp#msbxI1`8OBeAub)~B3#1Q!NO4+Y3u4=39 z%MCm6;Yp5G0zH7{vl7Tpo{PKIGFgE;VhbWF*ffyC01PAifK-_pO!dq6S_!9FvdII; z6m3J!AHw&3_X(Pv2lPc%pv2g7jqc6YgKDRC(Awc~ zVoJOMqs4lHnj|B{8k`cH3Yn^p zRD+Tgd=1X0Ir5eLb!xIkz@(qI?JWoEMBiQv)lDrAym{V7#&G++VPu}J0ch5f*9be& z!MgPLi&YUKcnteI)dM=)^glB;-LtCiJ2K+pQ;4WV)gr51rZK6N&zKsO zOiD(j;ImVpywx=+i<%#+$;h%L^up6ETN4hrG`y#-T-r3MX0F`v(JOQGG0QF?OC>wxnjoF&gRQT8fKqd zj-2^n%Q2b-X2T96x6jG$_i?{Ba=o8b``O8D*W&N*Zr3Yo@9*YY zK~yk0pgjdC!Phs~&>cH0)4#ynhW}($YTt&ERoJNY-KP7+=SBo1P=9NYMc_yLi?PaLS&h&z?si2KHO}OFn zoSH_wo!Su=b0iIf=In-nU|3p?A2Xq1B8DsTsA}#&5str2@=lb<3e3C_JIoI!%9#26 z&g_cOeYg4jsxXlY4%rXaq6!2&0v-X6AJ^LiJKwQIQ?CI#f{Suggg%oxP~V@Vcaq`R zG-R2HU6d_vD->JBo(G^yRJcV&O8eqHnpj@W?MlaHE`3eqSSBQ8c?G|r={S#lL-Xy` z&$#+oIqC1$Dr{=kB4*lyYg(HkV*0f>QxS`rO5gbpH_#0Qlr0KOv`fhTdU%+(U-j@L z>=JhI>jdrXWbNNcCBij>);W?eCnP1&0@cS6^iy`bq&S&~A1Tg-skG80M!+S3YYsQg z8yD?Lcm+q`Cp>s+JxmFS+wM4$x*sw zam_j19|#axwZ8;K-|T#n(I0Z6m2oAV-VpbqZ1TieM#rUwMFREA75TWNM6FA z&h+>4FAs|TOm7R_;WYYt)d_Kg{(T!10RIqH1zF(Ij6p?Qhb+Mi;*VGyQ^}fz8C%aN z57{K<5TP`8eOnF;pxf0@SoOY4>~H#oHcS-(AW9y*Z6gV=uz0gLPTROhMV2idF~gM(;>jP;sIPDu@VU(7PPv&yK+rAPhs>!a`X_DnJw<2o`IDsUD(pY9sWLRb*^Gx6*#hPr%}<@11zBGTNT~g++$Y56*s^lvo3zGY;A>snc{Gg5>tfb^ z2T6d~MCc;)5WWsgP=}a7$lcKN0830)XyoES=F{qTiDq%6RGtmgltqe)be3D?%h4Z! zC}Lr=q%WA`2tNe5)tF%DW$6RKHK4OX(h z&+J{qv(aT0_w!f9w{Bi{HN-cMk!7*t*9xpn%FUvyUvFn(F~a-SL`Hf+-W%F4{>EQy zAaCY&w=lFF?`c0C&te0ge3<-BWw@?Xsm2ce%g-T|w7xifU(8vI_(APt(uhPe9Xksc zp!4ow(lldKmaP*K(`(y~8Q|Ce0q0BIH_7&T*Ee_nB*d`EaR%e`(vaKoL-uwj;w>-QjnlDnOx36Zva5%i`5;aHbm=P|>|svc*i5}jExB(|#!J5B5Np7;Ls zj?K~v;9G9ie$42mW?XOc6V0x(4Npr@+anY`3qX@$9i}1Mi}@>u7rg;w&P+z@k!#7# z24G72>&%g(Yp3|}p9#LvSUr4sA*ngsV4z)Ymh~zAh~E_6j{kR2v7;!T_}PPlBVC)N zgX;h1rJ_dSPwRd48i25$L*HzmbA z-=A%S>17_-?<@}6^6*VkKE2Bff~&HLR4;&0MV;Eot-b?n1aSM!U-DvWuQTDdL9^aE z>iS2iHYX4?gK6YnBhP4}DJwF|e;Ikew?0|hC*>Z@xG+f+#1G1r&$y_1D~4QXsr)a< zyPa0ybKE*oA$~5K-JVOWA3+giD~V&E_G{FpsHkvXn2-pHPxv5N!6NEWYtc?Bx$^Kj z7b>xBhEK9Y-GME$*Y$YA(kir{d*!H6KYS?3{&Xd`8^>OFSUGd)+`C>ZdQnob%kG$A z4=rUmUL5D!Jz$<<6kIUx?QV@-=iAmZ^IaFf%{f=X)pR3YOz7c1m2i$dwa{nlrBh^) zAF=BmW@qr(Qls8JIILYwlrYZl?hp))2&A|IlAMJ#4VujYjaMsj0yS(+sl4J?bU|h; zrT$tGdMJ-Bszy%{O^;mw$#jRRlcmi23%e&TCnf*O(^21{NO{?y)a7@dYHEEjwPtXy z_NPa*=IoIci74n=kP;UMV!3_kG6@M~<6E%IRU!H(shgfGon99FpcWmfy?xl;J%Z+T zeOEJkD}t}9ub^9xuprpPUJioE=_UkICxHnR=qlNUDz*~S16}Di=8XnBsRfd^6IG?( zOJv66J7-k!rgq7RpDYr8P(|<2oo)XE>a}zr8w*5KxHrw8`X9h!(sDEoo$hWRE zM0>{NshVea>NCfLx9dvNc7jc({`0OLFW%odUZAWZ3@f+!i`J;t5q+r`HeZ{w(cQPC zpP&HZN^zCAay)o?1l6wwmyN@A3UtU#N+Tpfw~M0W#%^N{xk!`nJa$sNP*$=Vt5YV~^w%54Y7g4JLJaQs~B`Ru9QGVOYwFfmnC-ETy|x ztYlU)i|OE%jHrLde@JNdV!A;Tl9AeSdIG~?kaV;KmViUzwksPWX_XdOeHo$dADmqk%cPTx_dm-)4b8~t?B6t zzHK4LRQ;@Tyqf-wMUm)ucC;ukQjy=WH__s4!L8uFAMESiC=5#zEJ}VZXlXDt3)z_`r%}qQ zI_zkMG}gdnD07xBQyKl62G$xwV+!Jdi%L{x(Z)Z!9=rUt+o9hNO^Z22sH8jv&9JN_in&H(U8p(?_e}*$|1{5ivah(Z z2hZ)j!>z;{0P*^OlYXEuR(Qxig6H)I?|@V?_95pQRq!eZg26RO!h*G#Yr!#*Yd@}d zROG_6BpCCwXIAf{23z`CDnTqsY7{F5jafdkLJA8BuSSbntf|*HWBAGbYVSg_x$}&} zm^&%Hl#=7nikAiwGG!o1OhKqHSOhWx35k?MN+LPlU04XKUUWGzUPQs75XE(g=j<10 ziljKkaj;d!{^9MhgzZ`DizFfQBv$}uS&VVIxVf^Y%ZdyhZo3d3u3Hcf*R9^s9OqUJ z^8yL}ilVpc7=BDt49*S<=~)Z&YemtIO%V(MBJdbB`Fh4yn%yTu59Z zOvsENB>p&v_)btic*smZ$2LvJwgPe?nFu;g3hqY(I#6tmZHf+ohxKkvQHNKgWKSYr@y|ABEsI_XOCu zWD;eB)ouM^@$SFm0hOd0&AQ}iGLF)WYbDMa zQ>l5I$(T}_y5Fq9JLinR;jXDX zMoQD)mxNKW*B?7Qp8)x>0YRuu#5A!aB2;j8F~tdyRp-@hQdix)XK8Jdr_!+&>FpGO zlu|BYf5Q@TLKjm;nI9>N%DuIsEjgrA?`B9)vje2tcxodxq-E@p1K!M~$ElGNgD^dT zs%pckx*QTPPD`QQu0KLI$ubtKlk>+d>h&IWa&7|TbTL0`woDy1^<@CI$I?!qCih&W z#!00rtVAtFB#xpI@LRD;5qmfVc8n7N>^^?+v_nUySx-ZTIKjC zwUTUd>kS$!kR8BdyoVO6g07-G+n&&$-6ttE$TbdHwD!v%q%Y!H6UngKFjfTFmq81A z!dGc+jl``GFT+-=hO~QgClDXqdZemGu?Y7l*S6z$)9Ye|>jy9(O|qzxdW!?DmC0KR z7d=i>ndL=~GUXq7OeRO&+nsjLsq`pnl^3fPy_#=2u10NiVDNj_x%t8&o;{~oj5e;- zm&?H!*ygXVEME}u&;Qx<;ODELfBP@ET#;t}-AM zB6gUT74P_eWq$H8__z6~q^%HX>Hk3xooD`k2x4@*9_IKWJ&sFFq3)DU2sCIi^ErFe zh=J2rZ-E4g%e{IPOV?G!u^ zRQ^9QEK1E%d0sih9+!RJPM75oKe#HbI!}LFYCO(xH&Ezev~CZey>s52&(@mCU2xbD zQ$S_nUIvd@VpOInw2-KLzYI#-&6mv_LZ)asc6${*E<*3sZ`(Pk5A+HmN-eu++zLZy zK5y9=JPQ^3;r?EEq!c3he?*7|b6B*V{{tbKa{Rv#B0y{P3n6Cn{(}%{+-G-)C3%-8 z#kv|n652Mu;wzzE{}o>$24YG)6o;n!G0ohu&3;@spmvJyKC^l}puVT?{l4m9BZpB% z%w4ze2|~8!xpz0e5!{nJv2Z&6nZewow~aIY5Ghbrss6pA%$vtX%=;S9;$)IC2R^Z^!X)oqE#Q35dM8bZ z5M+H(`50lI&_$9UdFe!uVxC8Wp3R(i>}oO1QR>wp_-2la;c&4aUJKuPvj=TNbT|^f z3`A&5Qx#PMPpD|t%`WIUet4U2F299FT&XCV`7uCsoUT$x};!jM%;>Vx@ z;w`!3$FKt9AqkO%N_~IFc0&<#^tsu92tfoRKoBAb5d;fB1RwwvOnoCnunVqDaOmPn zqw=0AtZ02yf{m$in#@Kz(v3BW`w+yg}eRb`RL5y3@RLxL)N3kjq{CYsg4 zWBF`+sX(PjEWnK~xXVc(+(4O-TkbGrD!zopWD;^D5pHue{c4mU<6RlOH%S5{-DaTk z_nE{+JT;V6gJIkP?rNSIRio`@DFtIM!rvnBcY7*Y{yH$EAi}v z_ClM%U62FQ@tB0n{q;>}OvK-l;@XlX!>OdL_NI-RX_$7yqj)Bw9nD80FSQ0U_*V&$ z8`H0?xMfBeq%fHXO@!QoAa!vT-_}(B`02ep%M%Qx65xVcOYZGz1pV8nD~06$k55;U zW7~`)g+y!vMkVDx?%YDuN8+~elEoi##JbZeCXF*eX2vjR^%q@_`dnNVIGR$QJ?q)wXTCi%GZH%2WkNt@ z_=Adt*o5&m;5L%mx@Copu46wAW(=0c1AyTUBaTWe1L=%VPa7ff{z;!YRS`jJOK>$4 zB0X}M#@lpzlG5rBadj&~Z!u)V1BRtd!{r98M_jH26)<#GsY#n=VW&$RWqxVMLia{cW7ccS#U6#DE*@^&jN$au^(scN@wi{Jn4b_fw-&Aq}S zwZC(EEAnWzS1SdM^Q>>)t(q1F#7$8q{n__t0vvXWQL_q=PE$w(Yokz~_Z zL%q5jYtBixu}xASe+EmFINMwR=kw==Qs|Fqhj^@=>NU=GT;ZBc3GKaB=>c14F>IE@ z)%xXV2H$sPUz~2Z`t|9f$%VVu>F3K+v*yjmc`t8P)9#dk&yQBpvlx~TwYHYsr5I5F z$Zr`+7yG>>sCBJ|N^caE$tj%TBIS%}u%nu(4k1XhPLViLFPb@HPjjABF~+f`(mBQ9 zZu#Sef4vRw6$J9#P@F;+_o|&DTUtgVJ;}mgO*^mfC#AG`BBEU!Pii)jGVo&K(t1=j zq#@OSG0nY(pX+C%F^!A-w5j%SEIMX(YPDnJK&Zru5I8zs1(3ebszx$6HILN6j>zUaxf~%$1UzaGH-s0ttBm$rS zWFT@7If!hARXQQ!U@>>L)Je4l6R#NMG);iRCdiCrD&#p=DY4-?$1v%RRa|~TN-G>z zUlw_)qPUC7=BmS#aN5uYuS@&u&IeowqHxqLK2r?#OhM$*e zKM;T$LIsWwcgz5GjYSc&ji*Vy{@EY*T@P{mJ!G=pEPT6XKD6`TQ<#Z2>mJCY z>FuGbI2QGR%#iqpyhOf>5^BP)8m(l96fHG!>dTn!F}t;jG68DrytWLWYyNKT{b@E@ zJi30|FHS8?Fv|Ic8d#wvHBe3ID+m)E0NIpVvn;9#%PyY*|3~wg7HmHMm!mk6PnP!` z?T6e*{8;@<7x@wqi_lq^0!$%h7)RmjknOX}&^AegfZ&=2dM1&>LbGwvN|D82FicKT z9*-kQ2A90~5==@L*q1$G{(+jI4o%@x%7x~VK@8^%Xn+FaT4+2ayADGmV$3arma&Pl zbYBXo=?*0`Knmb-H^5%E$@6)0p=Oa%LgtBI^KZhNZu}p@TbbOn2D(%2)c4Q?rrk@k?}?a)LXK7F!y zW9Cyr__R@!Zar1(jDH$kr zyh20Aq)w|&H6im^5OH~{E0!W+YPEVnVk;vQpS_Fk-D&6YEC_1osjF7a;+r(9`jfpX z)i7T9euD~6COzRnjpXPFVWWVMUM5^ojU2NqQv;&a<8RmEotBWfpXA)gV%1};oyh&8 zo7jdXA8`wFu)2|I{+M|i9Y8A;u1h=z8ct|y3bW2A%JZNptn7_$!9?ZV#OO)3 zt!}lCS)g=8KxrPTXm@LMYjf_A&DHG%j%0hcDu1LMr3_>{evb)R-!98UICrS;XbZpj z*ljg2*^E6pdWSnMVa+l=I*^zEWlAzGk(>ZdO}t7tDiO+r^v|(&a>5r`Y#gRL&DT_r zG^cKh$ObzMF(n{1tOW>(_EKU(A|q9Bb1Y+izhcQGC}LT!D;ATz= zK*5cGmiI=p|vhhMbHODKq zl7zw@x@Jch6zXHcFaX5?M+QciaXc5)0zNJRUy@&&M1$4Hj}_(4!^{<3$?N83B$9NZ z;>A(@c2f9~rDxM^kE)~OPiq7EKu1R1Q$gID+!9X?SKAFrnKWAh9Nw5xrBX~e=d-FN zumdzXVWb%-;_7pHW+y5l4&=#ZFdrmJ=FUveS><``A(}^U7RV^9=ZagML73bFw@M4 zDB7~5`q607m96 zqk=Ezzc#g~Ri$N!z8LNP9OxNl8XHm?FTCK2%+Rn>i-lg9SlcZp@=^MY5HjtYxw~>+ z4#{Ngc2ib6jISGDWy>_Z=vUGMoGg_=w^Fqs zZ;MvANrf^d*WAbR`ByUZeigT8MlOHmvghr*6rAhzT!FMmswZGZF8p+*pVh~0Vrf^l z!eq!q*Mu6zPcD6yk1|!DyzZcBfQ7<2$4y$-?YH|1uNgPbvMzN5TxZZY%6PJ17%tcO ztYO#)df}k3IoUW%vZeb#hU6Emo5-M~!N^iGvrh?$AR!-V+)vS-JEZa5)TotG_4X>* zqluKTeApwKU}Y!B&346e4J|VV=J7RR`{fh@44bAGjW>PzM>fZH1^YwXPTbgO4F!oe z8@!0I-AZYiVxS53X?|d=ed4RZXwu9-7!E24(+A|!j)NW)cK#YeHgV}HF3kDwWyO<& zVc!5IUw6?LA;&QTh-|GzTNI&0a|;cf7TT^-)l<$5L)6GtSq7p_I!YD))YRz7XwD47 z^!Fm3(Q2WhO*L=YvKuNREA_GZl&f2HyN8>TElqn~rt~*Sb70TG^rkR(CVr6dKeoKXHr0YuEBNsaCEDBCy?YTJ^q2>8VH-OmO6*6pV{ zz6Tj(T|I}FV&*g*ngr;r{-c!ZUBdgoI{GVhY4M38$Qus5*e1wMJGV;Qnq~Bfhc6_q zowbl^T+%+Ax|gP(uAO9!F|7|{qHRr}9yeE>`Kd*AE5S;~o^Zr_40PPPnUgmB@NQps zah|T#w9_D-5=6#}{g{c!b;`dmGAC^bra@o^o8T$^`t?|UNb9BXSMoLpU55iO;_5oWp=S+QbR`_I8>1&Lqh~%V-T* zGF4%t0-0S|);OolKyGmbSxg!QmGsHK6c&mM1OWCy3?UahlL&DJ>r9e)+=sOA@19H> z6->`BXCW|tI_Hz^Ygnw)IK1|H8ZP$T%w?|Mrn60_lP6aHkQMlmr^FfO;Sj^)n>}w0 z$UckP`KK-a?ch;Uz#Q^}qjy!TVeaM5Jm_vo3>a(-%Ddmsvg_36n>5XT<#OjHv>KLe z$k6H!e5_=r9NHH!NiW=xw+jFPa{r66w~UIbd$&DLO+O?=reA#=gxt=wD^U?G*bbIW*qH)^@ z%KwOon#zGFEm`U%M+8hwMy)<-H51jK{`6nf)PUyv%kqc+10{X)Kcl1(#x_$d;%R?^ zgR~9m${+sQkhxR%A46tpUjL)hhT62d!3T$L>nE6cXWb(QykAr7knixVkR|VsRN4vV zY~Rr9B6U5@%{!M}MreITS?}>hs2iU)!+*Q>(loROQTXe}G&&?= z6aL?dsf7RS$AtBq68Vh2VpX8~gM?BpRXj8(#KzzH%L}p<&mqR1nj3r|OV-sXE1iOT zW!cZba{Tu4@BF=~6l7SB?b})mO$$Swf<=?`Z@)zI|E;U8iE}K+{BQ2-7pVJsJg#T~ z>b|BuYEu;uV!1))Dup$fPkQCH(CRpcSO2bkji7zQ9Bt6(E$oM(jVj{7;L!5Hmq38O zpYh$1*UP3R^%)J!$9=@L#Qx4?QjZ3tj|LXf1O&d-KJPo&>lc0&F2L@Pnb}C3(VsH4 z;n2gyXnh#5;sMhu!~WoC?9-3qpo>;cGAqtN1h7d zNV&khJ=m7MP({B^aV2=Miu}~OqeH*bz1{MF-uuBq&r-B zt1sr7=dvRvF+>3FV)laiOPViHz@+PN(gJK4YS@qbcfjnFc<`no->sT|9RrC;g~(L@)A{D1A}8$1V0-XDAZ6Dy}VGE`~Qd}@WYrUC8h?Fmk? zZKLR%Y-UnBR0OOy;4YqUi}UDNgq6FM_pW-BI&4$-fFZ%iXlG*sy@l`jXAnO@q89~L zJi>CZLEDC3297Awa>e3st?v$oAmag26EX%=>G>ml=(DLPh{e1yq*#vI)O*TR8QFZP zqN^gybisA-OgmbPKrfUG8`1)VR!xe!Xdelxvq>p` z|H7Grxw7K9w{!m!Nw9T;WGbpKbY2Yk>L}<>kKvcBpB^aA+U(M+uEleIqZ>;9iEfC1 zMmMB~Mp7`^OWs1BkRPxw3*dI83HpAK43E}hz?zetWnBoTi#ZJi^y(gb+E8s(%ra3- zYq(K02ccQlsR^5d2+S#}_Wnj9WWEc$$~MZq=+&klaMaXN|0hk6m_FnNNTYjGEbmiy ziSbiPKFr%K%3H}T!kgp3R=#P_K_T6bd*y2WLVL(P_Ka#>z@ekSC%|fR=*l_AzHDWW#i_ZaoSLM?fK_XW$-r^><-%1stSrLk=e|kqvvQEr+rsl;cAmAi!|?IhSHDj!wvL$Y z$%QOs@g5QJW_bj?X+?xX9Y~EqDgm6~#C1v5pLs(g@i%iP8cmW^mbe?CF@g@C&J_dP z7?|y*dgJx(=54iS3{#fUdA<9F4Edg8a3Y7FJkwZ*_tmFfA}dlne!Q&^@QO+pDXOFR zW*|nex;(udql83Qn8RB@UJE-7JigKaNti>LLAx>ovD~NnvhGN}ficNMPHReJ?$j1r z)!#KqI0)q-!{p6)%11>d<4dm-C#UdaX`$b6 z*^eK`Dv2Kt9Z>GHMMBl&&Yo&IJ8Q@T1Zlz@OGjB{^8v6zhWGCLdyQS5xz`=r!#t1C z#yPdj~1=) znK&@}Zf{ER<7qb91U8_5o!?#G9Zi&u;?Lcg4Z)=ZJ&3w2m0iq0dy@~~IDc|$Xzk}c zvvX_EqsmO(5{arX4v?MXkinS7$uD|@Bp1?aR758`;RqA`<}L`IIYvR5`liK6hyGK^ zj`@&S!LlXvpn^ zG=uVI7ClLA6}rPbdJAu4>`n&^B^ov(%~GTZpfM!9(gbUXo7MlrsY5SUb`UA0<2J3G zPhV6FQq6^V>YrDpaxe|RE*t-*vObBhK@557uj%*h|Bqy zhQy&x9hO}u26L58klNd7BGgxzbwwktUOgHpeQrS_NY=;@akSH^PfOr%#MwMVJx@Hr z%O-)8+;pj%{oo?&nQcW;E*epj#;=oEbWQ_g(+CH1AHUBp;o_MewSUfe`&FBeQaL6x zC;Mr|)8Fy3@G;0zR6x=v;vVmUX=_$Uo!`!>UHYGohk4uT&K4JCkh>;pIMh*fE%*?G zQaE1Tj^Ya|E4>?=tzwhTro*wy$v3lU-1IVs$Ep&AVKOPSGhYoBl7pBqu&v0$5^++I z0C6-ltAMx;;_-|lz|0Bl&yha_G7_BFO}7#oyNO!NA4u#Ft+~lW|ICf2o!}=#aYDS~ z65E(IC6|KxP{Z+Y%Him=INqw(2>zHc+&9X7Ox%PSqrf01ikFk(9{0i1W07WX)f5mk zHUn@vGiT+|jAoe8)e2=L`6QccMn}vP%+=_21@=1I*jlp6DjA++%nFRK_@SvMVG+=s z)CguxIh8QVu2UwOqT8uET&d(vo!%Y=@Xz0Wda)bxmSu1`xzJ@1F06;E{JvG;=lA;D zuw8NORQc4A>B@~B#;icB6p}TI$N3#~`y0pKm;ZDlw^DqrC9#6tl!8v-JOce;p9V}5 z5;a9yc7%TfIG=D+^PQ>NCQ?;=3(1bqb);cZ=;o-e(Z?rsovfAZw{9*p@uV;7qAIf~ zVLh0C$UjH4v`o=FuFwh#u?C5AY!d$q22>JJ!m1scyI9q29u99*7(qYj6a&n*`tZ}1OEDkj*F|p19DAqP8pGFs-#)S-RE%-fH zI+95X6wR2V>z(}RJg%jVW8&~2vRq znAjX5ks6_MijA>VSTmrO3kd^$D4x@MhyV9Sd-Fg!IcKqmI)xzKX{u`YAF$Ye)noY# z6;W!r!Il9kRW?#ihJEV^%~=0i&Hz3;tn_C?%O`%B-RpHdSj9$NJ|DVMm-e!8{{3Cr zG^m!CJ#ml7bPxLhG-2)g5cUJ`$ykXrpHV{9ok(&KM{;pq6_1YDnW2aw8#tI2JqK+X zeWtM?a;$EIW0A!4S;5l2ESKX(FoWk~SUw^{`)P^!@0*r(R7Scp`b1raD_kGzZh?=g z^ZDB{mDYJ$o)Nmu*I&Pd>SC|r$kEofe6~h#XBM!Cr>zHD2hUkcTKD(C#M0&4Ydxi= z?;W{65&B<(TQ|S{{J0kTbag&>HZRTWC+yWei*X3}d!Rl9`N#P{4^eO@wQSnG6g|4<5=K<#9YRm>Wi-Y+q*>0!EeQD}aQQU~hIO&Lm2zW4Y>EDNk8GrF$RY zLYFn-j}J3X1u`kW^W+DG3gxwk3*~R7=nCT4sSUs_E*r#7<>$b$Sn=OMb4X>A0j5K; z@#=U>@rA*SiN+yhIJ7{iP{l~GU)bNY7^Ikq(cYJ*B@Z8V1u9JweJ0!H5Rz+AzKKWP z*L>`8WYX7KkxZQm+eoDjC3ZrR2%2z{3Q~}#!uS@Bh+;@jOM?N1-W>`%}Oi*`cs3%OlBoqPC*>;iggwe z2?>0Rc)8h3p9aun*~33~&ifJ&^ayc?`72K;1&Jx-zivV~MkMqLH*6{T?rF+ryZs#P z#ZRK0uYSvmpIFYb?sh9OjKzeHAa;;O-_y@I=t3puxv_ZEOkg!gA#!d1zk5P;y3^ez-tk5peLSk!R?*JwmrqSj&6;u$mzW3ErKjD22 zUfxhP9Ttp+7x)7SwsQJQe1k#wB~&Ee5HNgy8K}}M<3Jy3uz0*4Yf;o+`sXE&+S_6( z_QM8P{2v_Xe_=qYFg&J`;UV|GElZEz-FGGoBcF0(hs&ZkCv2QcBfG^+0qC?e^Qcd_ z#&rdV2vse?d=lbYr}=r8p^wrP@o3`$7O<$}LeUbX6f`bv;xv$Ma6LA4FEI`^5G(_U zMK-Pm{O6Jy8%zU{u!N)GK_$>FsB=-7s^nxDZ~l?(F~P;Ji&$hCK~v&O1JORS^ub5t~-dw0ux&`q7Sq?g# z30IRyZ*sbeLIuuQj#|!Y*gGo*E^8eGw!jPQ+G_>VoM2oM78GN;Jm~Df&{_zJKWq42 z*TT;;q!QQ-D*qBPNL_f<4fe#UWD)}^BE=~9IZZ$H2CLsUEsC-%SzQ{PuR;ayx{pvt zAAdEN6%K$8*x@O%KpaUiV@CbG*HV!uqbAjFv!xHSB}K+v?mUJhZ?|{i?2eoDAO_)JX0gSnI&d?Z2w0WR;sCtyN$TZ&zy-fes2YHUe2msmbbCC z8VCIc)FVHNdjy}OZsKckiN6Vcg9*h-DOl+{Jyi#G|B40Tipiv!S-^GN0I zu6;SOjVmpsTGJt|Dbf8SQ?nbvJ!wfGtka>4aDh>^L>;#zLpH1CVI4e%$dYLsTnm>E zvJff+X{i^2T&Ji&GHEB_(B<==qRHR6kQzE;))Ddy$;K*Ecd@0Sn+HhzJ8v4#QUTnk z-f5M9bXv%olBjK%-|_3nmqlton7`*QmE_Vi2^oNbD)=UJr4uJWq^EJvpAsY^acOC- z<7t8$k42mZ2c>GICWri8tV0CMw3*EQnHrhQ{-38trqftF6q^4vJ*p4=ogSOZ>p}yd zbYd_oy?ueH;Wtag+yIW^%98AK#w=dD7|R&5Bqq~rD3G+3BnW?kv0e>{YiiZ`w2O5Y z<6$=PE7O_&vVV_Uno0u;Ah<>is6mEU!-Dl4{?$rh#@f zC*!0-R?v`6D}cfaC)6up!ssx*0g zcleyKf7WqC?Ev0@bfNsmBm#K1isP`A&l<_L5N4gPN@^}%H-cneuVzSuVXg|>ydAzs zy8%osg;mm7h7STtB?VmyS7;DD`d!km3uNge3Ur@norSShnpZ|PbVIm{YH;$(GR0*5UR0XE<3P23My7;M=5R+un~ z(AWv2@f>}D)BT&6SM(ZN6k4b1WFGmnsiTH{gKeLKWl6@}3rXDKV*j|JvBQP!LLldF z^PTc{L3#o$mIRw`SF6b<=F1)D&G4zVgyy^ueV;`>vT`?|m|#JOz2u&T$7x#WuIk*;jZ)q@UsD0<_M@oY$gE;C zn!bo)>e^(vs;wnwb}q+fzS2!>)}VmVp`+kT`Aomq{j z2`V;Ck6>@B8TCjLN3EA{@q}n=ieVaZ%UX_Q%TV9THG_Ey@fkL32}WxV z1zpn&$66PNG;$0k83plFkdvzi5cWgt7&ALK7tCli`dm`lAmaIZOhl6}WMPrnqfk}} z=!F#0j>EHQe%Pe*CyHq5qEIX2py_DK-uZlX(SR?u&o=i@7nZ^VbOXMJj6D@VOBIfc zj18cnk`Qx8g3&pPY#3-6OHzXWcL*u!%MRm%O_Xl0Fc3AtkZMXNnmff7FV2)j=9W{s zRe9I6VgVmnCP^~cz$rF3A-sR$|igq z1`VkMAB*JrT=RND&vSMx8Z{x99iori3~-{}0Y6R#&oPQwV6dCEyJ?_M6De3kN*9s2 zMsQhsIDli{Z-Ey`bOM6woEC@i1cDsJiX>Pe%kNjMMEcx@LRl~KTJB>LaUKAd)H~us zp|M!hlwc8v5AuHo_%_7d6h-=?ri9^fgeQAE2Jl7&Af>X=YfSChj{&5r^>C@Of%3#m z3`(Re9!MPU64EBT!ocKSC^%l~$1}HT(2z1PmA5nnz?Y+i(&G?I%YNIpa!>~{#^5!^ z-R4B|!{|Og;b!aL{)?Xb-072}mwBi1*}Aa*ok3NMQ1t&XU)dqOJLIAYuc+N7+KoHf z2*L-&;$;pe>*S1znsGfQmYSD-`$nXp#+4*t#H7<(_R(taM|v0TvhsNyj+-uO7C>M= zCi7mS`7q(y=3CWD9q0Uz)zSx(e<;~+M4#1%5;LHbY~(+bEbBz&h2eK*EP@gI4;ATW z&}7Kl)vx?#{9tWsMHjO&*)?gK_92c@94IDh`X3Y3e_^uh9;a%tGY~vB#eidY1J1=j z%~=q{rN6xmEHA?(*xpD8huN`_ARfek~ZC+$x!5p;64uL;==D)s?P4EwB!4L$~ zuErNj-bUz*cW55G`w`;uE#KLt5qU*`mTQ z;v{JMe0@A$J9w7;nZDxny%nrtl)2y`S*hB}Y=cJ9)>?92ZSvOIy;4=y?We{BzL{m~ zZPfMwfXTwtGQB)@kh382DLNhJK9Kt&P0h;5P~2WS!b~Ztl)1`=s8*1X&3Ve)Nv*|; zO0>vvu>DQO?~)(*H$AQ<-cBuxE!NTPrwN9hRs^!SyT8jzmbH+&Ome$$k>j8dwR z`S(&fSmy1YZ5mQ;RG1>@o)k2T)VpovGFeVH^CFs)lqfrWQCd7y*p1umNbAnm+1HcF zZA=#765p;NI68%g||t`^mh$aoU5YRja`6c0(#bbW2A*EQ?LRTp8Q)WVf5 zsKijAF-VbdJx2P`EM_8vE7M{IY{!KiUZV^E3P=XHEMF9*#6@e`g<*Y+xC)I*b!xp1 zvIV-l{QgNg_^sm^ovYBfPp@S&!fw$W8qsg^$n?qf*{`nMG04g#$k>PB8;^#SyGGHX z;uX{1puei`Gx6#=%;Ui>b5piix2(g!g1zcJhi2X+DPZNd2?|RNP#VC;g!+5w477UK z=n9lN1(%QW6P6?{C7#rd{yx6hXJoHk;L}dndcfR%kHTF_k0r0D+pnUSpDw}cnQN`~ z_dWcdEWY94E*U75I6{Dzh%?}VI%Pv``Z)?;Ll()4OK)PUVGdXe(N1>SORrVn3ZFpT z`+5FwbEf}&V*u>bAiC%As3JTOHn>gRLX!qyq`;CBR{ODuc*aPfDxB}p7b%Pv^Y7(~ zkT&pFzD@YxPHlkz7a=PH%@S3Z(SW?TMlx`zGAVsJpV^3~OZjW5`0d#8*sk@KqrL*) zO|){0a!W531KeC3H>Rws%e?&P*E)7#V&1({$T21_J?mvEmWK*Sf@8$yckeVTBCemq zB^B{Xi}85DVK8InWl7cDoYkcT&a${=@a}2Hs-Sc>9&)r9GCvSWWMBJTbMow4!9Cr4 z7pX&^1Ortg8tTL<_Nwi-aOUHLE8z2)$wwPs^Ka2Is|J*pJ( zZ+1UmyJEmt$G9_z74>7#Vaa_VDdHTtEmmzPXn)G(MIhRmC3x9kAmm7c{6B4XXE@fZ zH=WXFJZI~_#w=?NrEwZZxq*>$G;!h(O2DXrj3qes>6sELoJ`fxt|~q;c$W(qhU9hn zOM=p~eB&Z0pM&WVR2bH`v&4%H-RFi&6I2=2jf528*T@nYLZ(2 z9&!Robmj0^Hy9>5Q@YQ!eNRdWV-X~N@_FK8HT2*1wX->j9YYRpHNk>!uN{de4w@7Fe0pYPOv7ya_N^jwq7Hpq;j*omOE7BZZ5Py?Qx^dJ)e-1s~B#I4aR8_`m`Y(2i3(^A11Wz5SCnhf!vL zt{X+!UE>gi!*Xx@YW&G3n1=5UbwHWswQ)Al$BoInAe$m3#|6t0yY202UlGWoLKOGU zv)0h4n6lM3a247Rnj2C~DYXLi2`&sm5{E3~&Up{ihWxi9=I9Yhj5I_BQ8E2pMN*U% z33E*TcRs&fkjs6m<~>eA&fBF(dWs(5EDcF@`QCggLPPr4b0b>Vd0NByJ4lKhUlqn3 zo{f#c|EE2=TI>7c82|mvdh;ACZ?g>cGf@mtJiDp$TnLSR4finwQNKQCVnTf}*=~|> zyNYKiSh@XFyy>j_&C)->p0#xe*{Icr>&ccMs!bfWy`i7)@A}%sI|&3_x0+%$)TU0( z6;owG@_dlZl)<x8=x9+i;>3?Bwl zP@)~wt~1VKY|rthZ@Agd&c0e(JC z<)r6PkYPNw7r5~^-G(_v^4#7I_PbLGJ9TT2le#mqj8E0 zC;o`ezbicJ#~O@Scelhn_x#7xblwJF?0QL>syCFw2<|>vt|a|r_c^biH~3EVbt;hP zVVbXiy9o6-)X-7n14fSmMywoiE!(mm8#1?0U{zHTEn0-ghmPWSPr*&C?cI9d$SKg! zuj05wsLp>TnDF~wFI^D%<8{1K*aK)U2^gwo9eL zUJ;+`RN5h-B}~@CH!J3?ovPj_653M+j)^%RBzGa}2`fheC6QNUl2#_;nj8c6etjeU zm#vP%&Pl>xe&h!uA&iHvZ!1Xnmmm}~0&$V*>ZQ3N=u0I$Yn#tqu~lT9q8C;H0Z@v~ z$hF>!25V#HgvV0Y?-2(M_0(vZ2hMFz_mO{|Kqa?ys}LMoGh``~pJ|zj#xvn<)4?Jp zf+Krns43ApcsI z5w#AzCH`z2haK5=yu_B1L_xUv8VThJ_GDx=ZD zrEjYT*s8-Q7p8@%{T( zs18`3>6c5BL&{Q(mZou@;Tx3D8f7PSnOvU;CuqZ^Q?lDBc+{M9*vo7x@0aHh;30^OdTY>=L)>!Y;N`I;R$YXHMrwW7DON1u0OZmd! z>A7e~^`pD%qrldJ=SFl!-;H7Fso9cb>js<9f~K8<;0EG1nH@B2`QOTU9$BAEwD2xM z-TsBvD4(Y)Jyon{IG{}KX@TCX*GVZ3n1dsUI7Uw3w^31E2oeLlm7sNVB)o`*8YuK6 zM$Z{dQMz%jyOp;Loaep1nhupeExfA00-26(yIWKRTPS@>;|VpR*FTdYt7>j`467&A zC>t_RoOFkqM%azJ1~V?_0W`_bG$>L5ngn+OVvY1Iy!M%pu==NI*U)e9nzB*fg%EBR zbcGUd2_UFaR)}xgzk+loh(nc2wLy;UY??F(jn>F#WWz_Kdv7VOu5+1l4Xj^Ck`946 z_GQKjj!qKm$KRH3YyCit3vAfHjH)#oP_gR07O#3osWEAi@^+O5MQpEKl!XYzT%5MM z3%%f-&Z-P!Bcw>eiy)yv_#G2?W=uDQdzh<`HxhC&!fiuSNKtXre9uu1>+D2leBW^* za=ni-`-}XKTcCi)^%)XYNeo)I$5o-wP`_mT%Sn!lsPCPt9g!Zgyyi~)2-+@0-T2m2 z_C3+}%p)h}gcs?jJMT`DLAFu4<3A% zo{<`NPC3%9NQy+eN4{6(%xV5EpE$Y9sJoz~)ZMQCO#gvS9V{!jmf0nH@w`7PWur!9 z{EDXe7oyPqp)3~9Qof(x>a$wi@+orU*}%Gg(REG~_PL!t(M>DPtEI3==(4cVOQ?wh zu-VRW{{9i`?OLbbP4zUplKQqMYRRfU5551fj9xWM6aKE|Iy8E!e>bJP`B8JWB<<1X z>;6&9ihikY8jdy7^GsQ#TcpV~1uE~r#sJ-{lO7nujA*3#k)ih;QzIVo5NH-g4klx2oy~7rfS34!{Aq%JfV^qhN{8(65FMBKjanvimN1@@1m}~t& zR^r~y&%AYg-R5aL?Owipz0?{xOIrA~8@sOfK-gBnV&{K2d7BaI`Yll~n>dm2-9Q(t zH)hGb$RueBkXTH_o8+9$jW1;Wqu^<2E{9MX$blV(sk8R3;N=* z-@2P2fn&|qmsKSS!{vv$Y~6dOM!oE_Rd_#ZcVpp{9K!wQO&wad z%^;~xA|4}hVqsf|Q)~z*aQ+(%*IC;^C|46_{Z~-=1ufCuch!M|KmWZGs8_E#=Nd-}-u0;1~7oSvJ-(W%vDYJxSFnpyQ{EcoWZ9zu&Kr zWQ;DSvz~6X89y2SRkKfXNKyJBpOX<;>gx1Q3_3YwPHwA3U$R1fru&KdgVLBP zO`zUJ1BMUNd-;vCNkT5E6W^mKemUzFcbsCV9B_9SAMk7x zg>ZU3JYw)aajX9X{m3t zM6|=y26mwfmo42$HS!pn$oKWI>le%GJr_t?Il>S3#Zi%HE(gTxCc?An`#Cv8;YuB5 z7TVI@C2LYKwum}vZ@GH~Akx=UzLTx=c9>-^yJZdC%Ey5R+JJUxbz`Z3>Xd0w#1j_1 zZ5pMs_naayT}V*$Qvud`wExLr60@aZX>1(KI&?Fz{8*ubXpo`;Gv^pCIm-QNGg09~ z9H-Q5$VuOBtG$g(P+4&CsR??2U`Z*bluzdWvf`8*Tw;Cl(VXiHJJOI$vzJHyj&CON zcPCIwyB!VP2~gPoZdJ*6U@v`>q`ZJat!Li2{>yz@^soo*=fip5O?RK4S2zyBa+g6@ zUKIWsY=JY++7wy*wa8df&ty)!y@HhPy7iJRxu*Y5sX{dSSHWsMpM|F{H+uc~CH*?@ z9-c(4Sc{D(a&T$5_<4<=`ae%kxmP=|_U5TCGU57q8PrbXaBRrfpru}Tgr-iTwyKYn zo?)2RWit0g^6$~H%%LygNS4#?cxtOVJJba0hm$`fn#0o>5u?Y)RAB!*H#WWd(;9kG@KTx zX*kKGeM6i5f<%3IgjofuK+?Pl`S26$$at{U55~jbc^-NzTH1vHIRedeX;(+aA0NrA z_ZBRO=EjI|pR8^V$jy}bD~CBg8rV&w`mK?Fif5BU;3^g*N-&l)W?Wu1Rv4rMf@|tr zYv5~+%q^|(&OEr@+1L}(R8}Vt5INo+w0H0QBN&h+VHDbh z89)x(S_#v7$cqcT5`uR_$}(jHh2S!4A-RpBANk60@#t!No;`$$6;NPooOPC&rqRzz zJAd`Ti43Bd;6n(N$s%TWPAt55`)_K$bUC13s!|x}BMYK0xf)+yo3UAi`Lf@u?9=5H zsqYfEvZ#m^Rv#fWGc~94MM}h&iyD>%UJJQ`BMp#;3ub^QHR91B$~mwd^ySY2AqwGj z3*3se@d{TmNf?}qZPHW2mbBkeaVLAi$C~G7kU`7|D6Q=t_T{?cYmeyO>F>>8MaBgp zQG)A%crTYep^3wC5s764BN`LCGHJ0~)MmPITyd>Q*oCl613g1I+>tT=dC2V#&}>@)LAd9DK!BWQjy)|+BR6u(+i{} zD~$NIPD9WP)ol!3{yza+OQNd-&UHRLt7o`1+m!v!VL-x1qXo{<8 ztUTzyL4SQU|C(u#!%sPYYWWoacI{A!G$PzYQ-8pbay#74zQ-in&S1@$=H z|H~m#EY|0qP$`gv4bWGB#UO$Paq^vlF2}HCw;~rGX?Jk^qlQ&j*~roc2gQa}?=i7@ z?1&Y-#Md{|at@YEL|{e@QM^B{?y?_S=m4nm2*GvTg>NBXoN#4eSrxRw}t4QQH}s0)^g*8%`ZBJanEQqBnjp5rRR$4ODGvO!>>h!yrXRk&HIdy zDF%-cw^JC8#rNxZ@w45d;^6AusS58o%ii7PYDO_M#>VPo1Iv+oOR>PFGD$?c$%x-snc$2MnC$*GRi>y@0-k*2537h%0yZMw=BfA->o zdoo-=dLn}DO#iZ8T8@2BeZI_ht{%@IU1_@T%QRAiYNOF@_V2LxMrapS03~dvH}X^Q zPkDGhL4EBg9GXtfyHPmF$4pgf%O@nt^CT}1e4?;vB^ zk^7=jgpm>OdPtM`r9JWG;o@U<%v<$wjDgSJ$FQExi{APF3S(-Nw^fDHTG66Eeh8%y zF54SbQ|O7cec|!Te)jy?f&JYZDuJ1AX+8Ey{9lu1{P_%%3Mw6q=g#Dw3NDB!Gz9;Z zz{aOr-!ASb4cq*me^bkB&dzyc_gLLgMiFvUFBPE*9J)@<#5J5FIA9^J~c;d8YtfOPt-a7?^{xjZ5elA+e z^a>~0vG6@EU|=WAF_0@^V_87A+!T2c9yhE05%0XjR zv_2%no{`_mM$I1 zj>O~eOxc<>=W~K+%(_OBQ9{p}`=%Td%t$jS(|e z2lnSw(!G)YNIg69@fXp1YRn~0%s(d{DeuC#`arH5RPuDa9Q7HSxkXk5L;iLtuOBLD zq+f!bkRB$r?kAVda4#u$M2GxiU#VUN&|k!f^PF5?XeHt!ObODG)EwUOa!Rq_;3V}} zce1^F5~%7Djb{FaM;jrbh$5rkCyI74NtvP_0zBcpGI2`IMDtJfF(Y|q6(aAR><-K^ zAOLccY=5za71jCxFN*BPha@`Mjc(I$a+lNhR7iXdaH+4xv<*N1G%`&z0 zDMqA^n&!Jja6lVMK59yjaj13=hZTnqb=#uy;cS(^TbyqCp+2@x5Kg@O)`aiw)*^Rt zrIx;F@rnENtsrSmO|J5O`Na5Q!m>db`z+2-_HPsA5F1nFq3qcAl|$LL^*HU_a@R5e zv9Qz#E!=ThJji+>3_v?80%7Aqd>kN921zkCk`ZNwBu>kr=B``r$Z99iOZ8L^+hi=V zth8;tB#W`A@*69CO%AA( z{ErrrLW&gV9m~+R=Na~cDIav>{DgRSa-uA{_C9%(rKG4c%)J|ARMcpqs#KqVrvsx8 zBYsx5G>1ci=am5Bn#jqImf559p5!0SADpclHBzVwDlXhcKb9>uuYVJFM!0u>S6{Y~ zkTGA}GW>!@WDx=nK%v6vf*Y2}Gz{mY#Xh8->21#qwHEiX1g!)ibSO!g)HioXU#qC9 z)i2V~rDGQ`Ds0c7Ww6NWjxTU@ir!RI!#@4qI47^bA009-6C=FYb9EK;kN!ei$@WIF zK|Gfc(ofP>GRtxNz=>8Q|7i%=qgz(Aga@npGse)`&2WO zYHgy>qY@m6LX68*j8BYPmIb@YT#hY4RSwb$szB7is39@s9kM=UE&oARzFA(Ip6Em) z%bbCt+!xDOb}gk+ToH0Oe1cuRDHSo|rL~AgQNtN`WO{)511uf0QT{a`s;RZ8lKm`4 zwgx;lb#3Lm6=JRg@>56av=Ujz@7ydzaE7NRU+A$1ayKDR(35}9aTzLe8e#a{t|pkV zk!s!}zgw5gBs+Vp@Qtc%IzoCYel@4C_k^E30h9C4;l}zFJ^>ROkp^9YD2&5FXJ+$S zE>boW83!9k;WR@{M|FylP#)B0w)cl3Ktc|GKk1Q5F0Gb&&5_g=Gu1UrC-jc~sM@nl zJf9KL7gp^Rmd}MAP9p^|miQHM5CJWjv`arR|4)^XIAiKwa7ZvZ8r)K>ICUr((^ZI+ z2PYO{gHUIMPlPhea3GBveix2fHTudiZOL>SF3yx{!}2cCwMX)Z20NUKw7eE;Fsi+g z(fagca;mi1Lh()6gM|@~-ur1=3n5cwEh1Cp`f3JAVkp0PjIubZRD-QeEuI<`c8<7- z(L?$lyWJvS?MpF@MisV1U!($1jWlg5r9w!pVriq%^ z4y6`5#e!CiMr&9qQ}DAP-_|wLkiGRLe~g7msFT4{h)MtD(tVT}$pgk;eNQU&tdH>g z^z`!h8R>ay*K*%i;K-Z^Fe#Wvy7@WBdzqnkf=Re^6+{z`ErJ~W-kei`Fvn4vz$gi$j+*y_y?UQ z6`iTY?;ilQY@Zg{YI23-TzMGozWmOujBMaq8nI+q&#r9K&C~jjk6d4_*Dm7FWKqrF zI}*Vy-#!wZTF4b8JnOo(R30=_9}D?~S}-r$D-fe2NozIaj8pW^?sn6xHl+$>W+8H zxH3IlAD(~)S=RMF_;Z}_Q)wnKd}f7yxXd_^csy-p_)MKdXd0~jIsXWbF5b*MjhAT% zBTN7IRIr(yA^Iim180oyA|buLk-V~0%m+4#A3tX|N{Q7JH^S<9u$#2yF*an7tFf`k zDtmwqRmn$8Yw#`+bXtywS&4$G#B#EmX+iVZ-txW)fpoFqkpZUNP79B<+M~A_(cbkN zhHT}ypb+nRDyTg%>nh zqekOKo*V6ZR2A-XGDc$SsnDuhHp@kgmCf$W4`qrV6m(gK!#-YkSWJa9!k;>-;nt}p zGDG-~KLeIlx*cevp?Fz3fS1}D8dhD3qKcbe93-wtmbjr?Dk}$LfHK+^AI(x?h8K4w zRwyGumwt=P%ar%c&768zdc;Z#2#l-ikEKQ@Zt+e$w1w`Wlb2gfz8jM#%5sGyqBvvx zoZ!{qNfLO&c`!taAWt6}w0_1(xXhhvuu7tsU7rq-j5=h1g$dM7}3`wo%R5_P-wO3Qn$;|>u|xL7LRvomx-n&Xvf0rQJSBc3`&82}PMq+~9AErD zuO+bhf7;oLsBJYqBn+YwTAXNx=3Ew##5aa}2ODXaT;-0{=m9_ae$LDm+zjHh2kTx3 zg$(wiYsnTjHQwC`zO)F69eJ7_Jf3bZ-t^rXouSVruscxf3?`CL^GiGV$ZZdnrU%55 zNbN_ByRv5#FC_}14AK_5#erw(md!qA(Cq10A4Q|ZR?@=%=JC-Y6X5es8GK0bYG204 z7;EY3?_y(6%bcr<5o&P?298Ajbtprh$e)28$_R#;R;UE=H7)KP$ab}HOin?dUA$SF zMdf^zuyacDX@1zeR2m+l!<_VZfmE=W3WY>xiLyU+tZTiTk*8DlVTM?Yk>>)UWStke zq=0^r8Ke(WBMorEyQ}-3>}6+F-43}?TFR*PD1A^A$=aVI@a7Ft7O{` zJ{4MZ6*sN@@o*5RHZkMcDllZBdBX$Eu&I?7zMT!cm%=Qrg~Rvx4r~1z(ClS?)ZW_OTQ`U&1Mfau@88<|YMf2kcpAKISXUD-dm&ps%}y`V2V+i? z7l}&y5za>XVEiK8Zd(BzzN%0bFfFbn|4lEKp`$%+D33XtMbIy7-^vF{676+Y#2G3_m$-WyOu7B#5vQDdB9 z4GquOwJ3ihu=|zj<==L0rK3gfNUb{xroFeBJXWw7QV&)L6}%Ku1Qr?x-4ptkwStNzLYMQCyJm}c#*r)q$d)SER_oe+GR@|M+Y<<)MJnsJ|8~Qu-REMG z+GE*ho-D8fSd<)YH7`f#=qMyk|1J9>uOs_@T-=e`%(91xut5Wrh-}a6$D|mE`pb%!s%?5jIY4`mz5DJG!fauyp-A&|1ZBVK%K+>4;j5L=lZX z1zMQ(pDF;r*rbLLlRyz)zx>}+fFe^bmHU5G063wfNVEk)%zmsh^l*b&*RvEa34u?* z^Hm5X1lca^YDD$mjUHe$^W6uU`@P9+i)YU+apv3ftQ*@m0WDd9UF`wSO+Fj<&hcL= z($3O713%fH_}^;gh&%LySLkBDM-@NKf95Z>bruh$JtF;;=G0nbbPesyYWZ&Rt8r=3 zGaylydF**42jYipwUTbA_UQFq6yX0gJ>a)rph(cWdyMypi$%>t7CP1Crajvvq^U{_ zk93~TQDroOVung*px6L!6S(F<*NeEtZV}`1X)8gc=8qq)kCt}4zwzNVz2xyol*)4F z?mp<)doQO|Xm+e{@hoU|kZc?_&3^ppH6v@d=+w%@^V$fE)z!WL(f$o%>OS|IwqiO< z4q&`1O>D06U3bq!73~vNr6O@}(~V*hV^|)GHk6aU!@c~vM-Fo`_pnmn_k7J2y{jw5 zWPy2kuiqqA#o}u7rA+{0UFMKK(nx%eyVu4)%Rr|7dc%5QdEdVN#Xr)1MiE+>Rq}=3 zJ{h$}U1edXJdh8;bYkfIx{Liy(`StVZatck!v-}IVFfLEMfYslvIyjNJT~X{xAe2h z@JR+BQdQhGg@cJA!O?X4*JOr&xc{=Fd(Wd>Ci_^)Hw`qUrk99}$$!A3_3u>5cA2Ou zi&!Jjlt{ELFpn{7R%?yssGDmHIgagBEKIxDuUI3V zfl)92ltszMvrUE0WQ4r;2tI|Ng73yN=i$e#kG@V`4Sw&3>`vp10&R({qcQoE7@EN5 z3BW(lcl+Dv*Px4=P2++;ywzI`p<<6O!KmQi=q_E=pY=^XMl%M?2B}k(wmfM{da}}A zKSxT%;J))adhEQ?---)AIKRUPFQ?B~^3{i0*-q+FMGd&Qxu|>FsYRJ~c#6cA2Pd*= zUm+`YQ!r!b^Ml47bHQXXQ3f=dGX@s;>FWv=xT%HycB1Y=zNdgS!>^F()IE1bUf3!@ znh@-D1fjFsyBZi#4w&K=Z$Z!tLB}^-p&wuDW1ZM_+jjOzWf6fDeqKbocGIxlX6?EcTQ82$3gCG%5!h7MI2mA* z)C$GUl|G=AT=K$YNCM^UInYMKY#ZZe3vAW2`9Bl>uRU@W&SH zB(u5$Rq{2J;MdC51S6!C7%6rf9CD4`Wa1=|jX#dzT(P5{|+F}i(azUPQ<;KQ$tVRgUx)%}|mC2Z^ zgZ*e%)8EZ+8Ew%dHZNDa^kM)Z=UZEt0nF_K2~nll0cel}hILWtYf zP_`ejn4^^D90{4DmQkA)lrmywv}Ps;UD1|uJfC05 z-?!<=3l%t{$j8-SljA4XD96IXn^CHWcKgWZ+QYi2XAU$X>0e&2hBD!y!Pd>~K1R(z z2bE52bM5&B<;s#h!3#<&JWw?Ow?Ilq1k|l`uQ#OQLuM^i&lTeV#V01zx0O*^sY>kU+yXCG=#NmG^1sEXejkG#od@LpG&v zS)*&$Ipm6>#R#k8_QaSR9dSA|SP1Sjk=Xb&S>D7njY4IJDdrFBR?Scu!VnSwqncx_ z3U*`M(6_&pNV?GM)HQa?I=Ir*sA zh4+Vu>KJZ_`8^#9bd`2wVE^=w8bRiqB3MV?{J&BoJOoR;IBj`9!lU-`DlQ#GK1Ig; z!UuhaHleF_6=DAFzl96LAOo^^f*NFnJxM4cPkvLa+Suo`ecTXr@K-)T$S~-l#;e$H z;Yfxe6=`;@Q$fdQ57mQO90&m#e3t4SlGr_s_WrC0Y`phoF(s;Z9Y6Z6<@7iFst4cm zhn?}xV6m-Hy#2jARS%oNU@UNpQ}aUgEl|7LTd29p@E`0Z2EZgl`}I z>O)sK0b2^9$2=SG^P#+naJ;QWf5~h0K3JqKQzgB@2BNf+eL=<@;Q(V6{#3Aq^T#9y zg^JnnehGcgH`(z-6+1n);oQ1~$e~9vb)fHmfcGROl41UNhn}3@15RY8MKoRUK>eDI zH2jRWz?uA`zJ0#;MOpxJumvy8zzx$`S% zpOM7B`ivM>_nYk~SCMo+xfAR|(>!ra7kq;ahDa=N)05?t7~PMhjqT;vo15486X_AzuZr@&^H74= zk5~$5c;JeJV3HO_iQ%P@qOh=3V2b|miH(F4z_2wO^JVi0#(&Dj|EZmxD)p=jGeO00 ztYcfK?xT{aC=Zg#qPOi%TwuVJu|kS0-I{XHsUl+a=|ekPL3M(5*q&+m+^uM4twK)tpMrR7pHHWzR?;#(?-U(Zm^n!d=@9lYofhSV(0Fv;}X2b#alUHi~i&r&hu@HfpWoc%qxlb0kGVew>9aC|*Drp(Qn*Wf` z>q~9Vqm;hO0Q6#P#A0R996^)qB$GR7v3S+O*)lNAkARzpB4{e~ok%;HseFUbspT(o zkCn5S23Mp7?a*FAA+h7}ex(=Bb7Q;o3Bk_Z2_VjZUTs0yZI%DaP&bdCk-OTL`@Oa@ z_G3l?Nax&b^HR=WsNHSliYQs$x9*2y8`h(c9E2^a>7JR`wvXSq$u6(LKHmtskM14a zUWH}$?eMxhqWbqte{%i}aUPkM7Ff*7%{7&ax!fZb+HE zi#buhcsz|U-)CUnmxq{on+8l5-~Gf+Nr=jFKLMnA4?6mCBv2?t zoA-%VrG+*X-+-=wx!2Rn1Lp=MB26) zQnI;^kn{o`B)frgsLUVKokLxOouBJ-^r-dJxR45&pNE^r!KY0bCAeq^;l&m9N+})kl^8ILWNcxbz7)N!pjdxYOEy0QkZ*RQOq~V*j|+F zH6HLd2?UdbEOlr4veZNL(yQtN0|=ADdOlZ6n1A1FK?KEFj}0)hW4N!loG7c zS~g&x4-S{c%et`xP(_gOho6zAp}W*@MidRaB1Cp+=<;}fBHyCcrK3Wk(Y1aaNqRt+ z2T)bgR*dpp!RO`bjjC@2#CrkQ9bYEf>{^N>)0wC4=WSl@*yhXd^}z?Vb7k~6^FPo- z?c}b^pqKReTeJI5f3(`9|F>3ayJkQCw^lpW9&ZF5;%IIQi|lXEpz7V;PsZSpC(bE~ zuPvp|>p9`J$ z7QiDxKE>=>vs^SwbIpTv=IL5A7<|V22m6zYow}+FJr-1lckhtv7CkSBnHpMfzdd5m z|Fnjk&~o0C7WwTt=JecwC}(Jtcr_%PdPQpeL^X2HwX0lMC1(&wQopWH3Ez^e|INzm zKFI26Sw+skG@+`y`YB#xWy8-={Asedc|(1r@2|7uRcP{)lcJX@U~B;R!|=~sE{1z#*8-_z>a zRQU=k=E3NbeXFo@jT5pRr_62bZlMO=-j-M?lAlv(vaU-~z^33mp8t5>p|YD9D{m;n z>LJn?1iKapdU8#3Dm=`f_P=H7B^E8YS(6faDk_e|E6&#-+Mtxt4~^bj*9Yj$j;)#WD{nDXh^#Q+Qu|JtqY35V|8^*| z$Sc<L^W^fg5-<`H-59ta=(<&vrrEFrq#4YG!mS`y+ejsGg)#sYdy(y|&wID0V7o z#C?&Jd(B(RFwhgOEo8P)vH%-Dq)GF3I2V1=(*D5Ys38vj+t7~=Z4qGc!$mD#Leu_B zleg2DBZ&gxM|_=Y`lY7w!^}LblL;qPFV&_F*UCok3PD5QSdmf@?vPqOf~S5=35;e4 zvgA?yC*VM^f>}`Jo%o~ZnzD$4=|>dW-|FtL*3x|BO@r7}OABR_*K{dsc`0ib+!Izq zRznLbLiJj@L962Rui#hqyA-l13Gr)@G#aL2y&SsGZMvSsY)Pv%9lGLBq~qLxo;EoP z*;ssqb&T~M(bCsZ0-qn|mOfa%UBNB@h{vMYqS-ohRlnwW{b1V_JZsVdv7X2}C6jEZ z(^zpJnj%lXxqc{^j?i=m&AL)0qynLzagG~E3jtSkYs96;Wtsta>(>`Pw?fCfv^2=V zvaIQ&t5tZEmCVjNnv>53Ton%gVInO4klp$FDN!PFlFCoC7>)upBoyOj=2#(735$(V zUayKbwY~oUT&cu{c!rsZC~?m}MI|KHEtiVnC*Y~NJ~ATg%$A*!6zhe$GV|7kA}%F~ z16RD?g(ezMvXm3uv9P_K?2W>1lqj$Qlv2TfDCTL4Gtl^2MXW?_wa%)Pyz6rWt{zsW zjpsVF)@?1=wYrXoT(1yH5=veVWw@8Lgw-0&El4r-NY3@pfhna>On$%4Gty4;) z%<9I9(j^R5WRR--SiYZNEXj0cN2sZee6Sp^_80;@>pNN-)$|na!2TNc9q{3y7jc6V zAW!-g^~<&~`j*VkG&cV4X_-!HEXOjs)q~J$7TFd>D6eH&rU=OSI{Q~HM6O#1)rsmA zhiIa|Lp7<`o^p_lUz8a{^s3z@CwM2Gtmys5##9hwULQQd|EjlSF~U-0=yi&1+uH|| zK_3+7uZFDQdAP=~633+Qb}PgV(-H7&2#%Wdd?+c0XV3jU*Dgn-JA%)IYWu4U6gzDq zQ-XsjM43c)u$+1Ew9PP0f;8UM16`c;w$@fsEy_j!$MPB^2%qKdr|F9WthW5^pY0ty z9qR$L3{^0;cTRFJM+}BYUfgo<1-gWXtsKG~nLppvXODn~oaj@CQO%C=Hp-k0)uNurBExVXwwrH&NL6u+z6+gL`I10Wlv2)NKwc& zl;2YJ?X+&XnhS7?a6!k-UX{MY6$__q-+z3Q=JjED_1B@<+vc=;4Qv-%%F7<PGR)r1&@b())Q&+i~>rY5suks8|#=4iFt;VWoGO;X`G=R`-x@6NRXHFdrVu`=Kdzr8wyLru?2-{H0`MOyPB6c9vySao|-ZiP4x;Hjw@E1=#a3$L+T3DDLdni)aBVrrWI0Q z;ums76)B+)_6K}&u^OcyM(J595Ryib>pje$4L~12jqyXVcoc7qYa|P9BB}J+cL>C4 znz;m_)C&-%Dk~^SIlh=$E>xFG@c$e!6gO??8W$8XC_zFD6h-k(#FkNX0dWhrNSb9| zhBZFWEe~@_!>EW?DP4T*y6^HM+50u}b8M+YkKw0ujZl((Xl`mQBDW>qNKqcN*lfY2 zCNGJzbQVaPOO!(7UKLv*pohs#|JUq04$=bJQ-z7_RbFc$ixFqxdhmdva4pg%%9^{a zKKHiq4J$WAZE{er?G&iH)R0fkbHm6&-`*rBk(8=NuZO7*S*lze1B#AXC{EvR#tcUZ zeQ-P=h|q*X(EC|9sVH0#?z~qIsVoxuSy{ho!+OAA{5k2*HHJy^BgH(#GQ{t# z7ok9VbOlLz6 zV@ZLJsQaifpqoazH@ZF|x0#bF8E>?1c2Jc>*byj{xJLU9`&|-en}YlYrJ(OQG7fdr z42_!-g*pT8@ZV4L$k}m62R}255A$&=FtC2Hz{5~Uo_9U`iU`JVU?&|WpFyD{!$gu_ zFPDRr-#>&&o(I7m1_$x5pZ$>Y;G1o*K^!x;Z4viX)1>MuO@R8Z%4%aLgLpPSTEy>; zH`uz1Qob%fRWCw1MbXM;H|}}cK&Z*OhHvToDPOaJP;iPyHHD=E6n=ADhp@*RXwg^k z4c}u?k6~emj+bt%Hc|?~g%mIXJj+nT0`k1)=lSn`;6Jk?*a0^9z3}@WtN#sM@ zQ|;LL<)obEH^F^dbxHCh?v;QeHH(KW2A{#xxbBUv$HhYTWePZM4sMsvgFi29Z7i?z z9+gc44EGVk2xA8lTvq6l{Rx5|ezYh;>HxaLsrWqDzA!O#bDd68{-Sj6a&cpGO+^O- zM;d-uPd@N@pERv!vzk`@T+SIKOM>K4rtGy2&!D_kPV-YpD`(cmmX0o6HUkaNn+8o4 z#KI=*spDDdNSK4sXQEogt(N*KxD8G-SeNvz%YRZZry~kU(Ph^w=VKPA#Tm`mEE=x9 z2{4RvEMF+KmtpIn8zAN(jIu!CfgvDu%=~8{vmaH&Vxd!+2#BCCC8omiPz?G=shyM#mn~HqwohhiU{%oOPliLDwm>%f;v!Pam1g2*xhOg^LvUlZ<(M*93o@t&={V zZO21&)pmspmxJKeIP~`!W|XQgg;-bcEGAJ8yMBke+*iec^v%%AecJJ4Y0%ha?k-O{ z1DskvfX`;;E!MQ!dPa{=+b)ENTgWE}SU!&xgy~YhRiPd|5DnO@mwd%(wQ8}~6$@iv z>^&w3Nb|h6Pu;Ueo?wY{R_pr|;|T=YoNe0`W;*^lv-y^`f(;Q8$(%U83=j@C&Kdvs zA_UCoHxTGHaTl&@(otY!m(B(!>bxeBnNSQGu|J7v>?pF=%^w{AyYUvU8a}Y6pYFXW zivx85K`$?;@4sD8@@1}y}7YUwq>jq(XoHpG9Fe{*d z8&$56hr<8aG^m?`bsdkq(|cbp)Rgq`H^7*2dK+{0E=kv`XuRi#c<1e28AU!>j;d*T z=nuNCyZ~31hoShYvO5i5hc8#w`OPfm1T5{klgjE|)kDVJd`I80mox2{LRv}(IE5#W zuq!;Ls?_)H_4;5&_KgKmQ|*kA1_S}XJ2oOLiR{pkg9bzQ=6ulilf?{$IF)nn-Er!k zlV@djnt|yAaX=l1P^@3`%;VZpPAO_TMK_?*pPgb_gs*%2OKzU&c=w~_FS>ix{B71p zzJR9IebZ8Bw(11PtU`KS;6@Ihi|?iNmo<&RB9FJ}XsXWT4(pWig9`UGd!YP-N_^Mz znx~w%2M*b^|MVW6Qq!`c=FQO3&#R7> { + describe('when there is no data', () => { + it('returns empty list', async () => { + const response = await supertest.get( + '/api/apm/service-map?start=2020-06-28T10%3A24%3A46.055Z&end=2020-06-29T10%3A24%3A46.055Z' + ); + + expect(response.status).to.be(200); + expect(response.body).to.eql({ elements: [] }); + }); + }); + + describe('when there is data', () => { + before(() => esArchiver.load('8.0.0')); + after(() => esArchiver.unload('8.0.0')); + + it('returns service map elements', async () => { + const response = await supertest.get( + '/api/apm/service-map?start=2020-06-28T10%3A24%3A46.055Z&end=2020-06-29T10%3A24%3A46.055Z' + ); + + expect(response.status).to.be(200); + + expect(response.body).to.eql({ + elements: [ + { + data: { + source: 'client', + target: 'opbeans-node', + id: 'client~opbeans-node', + sourceData: { + id: 'client', + 'service.name': 'client', + 'agent.name': 'rum-js', + }, + targetData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + }, + }, + { + data: { + source: 'opbeans-java', + target: '>opbeans-java:3000', + id: 'opbeans-java~>opbeans-java:3000', + sourceData: { + id: 'opbeans-java', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'agent.name': 'java', + }, + targetData: { + 'span.subtype': 'http', + 'span.destination.service.resource': 'opbeans-java:3000', + 'span.type': 'external', + id: '>opbeans-java:3000', + label: 'opbeans-java:3000', + }, + }, + }, + { + data: { + source: 'opbeans-java', + target: '>postgresql', + id: 'opbeans-java~>postgresql', + sourceData: { + id: 'opbeans-java', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'agent.name': 'java', + }, + targetData: { + 'span.subtype': 'postgresql', + 'span.destination.service.resource': 'postgresql', + 'span.type': 'db', + id: '>postgresql', + label: 'postgresql', + }, + }, + }, + { + data: { + source: 'opbeans-java', + target: 'opbeans-node', + id: 'opbeans-java~opbeans-node', + sourceData: { + id: 'opbeans-java', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'agent.name': 'java', + }, + targetData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + bidirectional: true, + }, + }, + { + data: { + source: 'opbeans-node', + target: '>93.184.216.34:80', + id: 'opbeans-node~>93.184.216.34:80', + sourceData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + targetData: { + 'span.subtype': 'http', + 'span.destination.service.resource': '93.184.216.34:80', + 'span.type': 'external', + id: '>93.184.216.34:80', + label: '93.184.216.34:80', + }, + }, + }, + { + data: { + source: 'opbeans-node', + target: '>postgresql', + id: 'opbeans-node~>postgresql', + sourceData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + targetData: { + 'span.subtype': 'postgresql', + 'span.destination.service.resource': 'postgresql', + 'span.type': 'db', + id: '>postgresql', + label: 'postgresql', + }, + }, + }, + { + data: { + source: 'opbeans-node', + target: '>redis', + id: 'opbeans-node~>redis', + sourceData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + targetData: { + 'span.subtype': 'redis', + 'span.destination.service.resource': 'redis', + 'span.type': 'cache', + id: '>redis', + label: 'redis', + }, + }, + }, + { + data: { + source: 'opbeans-node', + target: 'opbeans-java', + id: 'opbeans-node~opbeans-java', + sourceData: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + targetData: { + id: 'opbeans-java', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'agent.name': 'java', + }, + isInverseEdge: true, + }, + }, + { + data: { + id: 'opbeans-java', + 'service.environment': 'production', + 'service.name': 'opbeans-java', + 'agent.name': 'java', + }, + }, + { + data: { + id: 'opbeans-node', + 'service.environment': 'production', + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs', + }, + }, + { + data: { + 'span.subtype': 'http', + 'span.destination.service.resource': 'opbeans-java:3000', + 'span.type': 'external', + id: '>opbeans-java:3000', + label: 'opbeans-java:3000', + }, + }, + { + data: { + id: 'client', + 'service.name': 'client', + 'agent.name': 'rum-js', + }, + }, + { + data: { + 'span.subtype': 'redis', + 'span.destination.service.resource': 'redis', + 'span.type': 'cache', + id: '>redis', + label: 'redis', + }, + }, + { + data: { + 'span.subtype': 'postgresql', + 'span.destination.service.resource': 'postgresql', + 'span.type': 'db', + id: '>postgresql', + label: 'postgresql', + }, + }, + { + data: { + 'span.subtype': 'http', + 'span.destination.service.resource': '93.184.216.34:80', + 'span.type': 'external', + id: '>93.184.216.34:80', + label: '93.184.216.34:80', + }, + }, + ], + }); + }); + }); + }); +} From 43bfa4ab66aae5f9c2605b7b819b3fa6aefc5104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 30 Jun 2020 16:56:40 +0200 Subject: [PATCH 13/13] [ML] Modifies page title to Create job (#70191) Changes Create data frame analytics job to Create job. --- .../data_frame_analytics/pages/analytics_creation/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/page.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/page.tsx index ff718277a88a71..e8214288900464 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/page.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/page.tsx @@ -149,13 +149,13 @@ export const Page: FC = ({ jobId }) => { {jobId === undefined && ( )} {jobId !== undefined && ( )}